From 33cc1f2a50d870b7d264ee5479068f8eee3aa458 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 22 Jun 2014 20:44:01 +0100 Subject: Fixed multiple issues with projectiles * Fixed arrows not being collectable/not truly hitting a block/not lodging into blocks/not going in far enough * Fixed projectiles not playing their block hit animation owning to being destroyed too quickly --- src/Entities/ArrowEntity.cpp | 33 +++++------------- src/Entities/ProjectileEntity.cpp | 61 ++++++++++++++++++--------------- src/Entities/ThrownEggEntity.cpp | 7 ++-- src/Entities/ThrownEggEntity.h | 18 ++++++++++ src/Entities/ThrownEnderPearlEntity.cpp | 9 ++--- src/Entities/ThrownEnderPearlEntity.h | 22 ++++++++++-- src/Entities/ThrownSnowballEntity.cpp | 7 ++-- src/Entities/ThrownSnowballEntity.h | 18 ++++++++++ 8 files changed, 112 insertions(+), 63 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index 8d2569125..db9dc781a 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -68,25 +68,16 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) { - if (a_HitFace == BLOCK_FACE_NONE) { return; } - - super::OnHitSolidBlock(a_HitPos, a_HitFace); - int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z; - - switch (a_HitFace) - { - case BLOCK_FACE_XM: // Strangely, bounding boxes / block tracers return the actual block for these two directions, so AddFace not needed - case BLOCK_FACE_YM: - { - break; - } - default: AddFaceDirection(a_X, a_Y, a_Z, a_HitFace, true); - } + Vector3d Hit = a_HitPos; + Hit += GetSpeed() / 700; // Make arrow sink into block a little + + super::OnHitSolidBlock(Hit, a_HitFace); + int X = (int)floor(Hit.x), Y = (int)floor(Hit.y), Z = (int)floor(Hit.z); - m_HitBlockPos = Vector3i(a_X, a_Y, a_Z); + m_HitBlockPos = Vector3i(X, Y, Z); // Broadcast arrow hit sound - m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); + m_World->BroadcastSoundEffect("random.bowhit", X * 8, Y * 8, Z * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); } @@ -94,13 +85,7 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFa void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) -{ - if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer() && !a_EntityHit.IsBoat()) - { - // Not an entity that interacts with an arrow - return; - } - +{ int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5); if (m_IsCritical) { @@ -165,7 +150,7 @@ void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk) if (!m_HasTeleported) // Sent a teleport already, don't do again { - if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case + if (m_HitGroundTimer > 500.f) // Send after half a second, could be less, but just in case { m_World->BroadcastTeleportEntity(*this); m_HasTeleported = true; diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index 95c494569..d45f1d212 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -67,16 +67,17 @@ protected: if (cBlockInfo::IsSolid(a_BlockType)) { - // The projectile hit a solid block - // Calculate the exact hit coords: - cBoundingBox bb(a_BlockX, a_BlockX + 1, a_BlockY, a_BlockY + 1, a_BlockZ, a_BlockZ + 1); - Vector3d Line1 = m_Projectile->GetPosition(); - Vector3d Line2 = Line1 + m_Projectile->GetSpeed(); - double LineCoeff = 0; - eBlockFace Face; - if (bb.CalcLineIntersection(Line1, Line2, LineCoeff, Face)) + // The projectile hit a solid block, calculate the exact hit coords: + cBoundingBox bb(a_BlockX, a_BlockX + 1, a_BlockY, a_BlockY + 1, a_BlockZ, a_BlockZ + 1); // Bounding box of the block hit + const Vector3d LineStart = m_Projectile->GetPosition(); // Start point for the imaginary line that goes through the block hit + const Vector3d LineEnd = LineStart + m_Projectile->GetSpeed(); // End point for the imaginary line that goes through the block hit + double LineCoeff = 0; // Used to calculate where along the line an intersection with the bounding box occurs + eBlockFace Face; // Face hit + + if (bb.CalcLineIntersection(LineStart, LineEnd, LineCoeff, Face)) { - Vector3d Intersection = Line1 + m_Projectile->GetSpeed() * LineCoeff; + Vector3d Intersection = LineStart + m_Projectile->GetSpeed() * LineCoeff; // Point where projectile goes into the hit block + if (cPluginManager::Get()->CallHookProjectileHitBlock(*m_Projectile, a_BlockX, a_BlockY, a_BlockZ, Face, &Intersection)) { return false; @@ -161,7 +162,12 @@ public: return false; } - // TODO: Some entities don't interact with the projectiles (pickups, falling blocks) + if (!a_Entity->IsMob() && !a_Entity->IsMinecart() && !a_Entity->IsPlayer() && !a_Entity->IsBoat()) + { + // Not an entity that interacts with a projectile + return false; + } + if (cPluginManager::Get()->CallHookProjectileHitEntity(*m_Projectile, *a_Entity)) { // A plugin disagreed. @@ -316,8 +322,9 @@ AString cProjectileEntity::GetMCAClassName(void) const void cProjectileEntity::Tick(float a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); - - if (GetProjectileKind() != pkArrow) // See cArrow::Tick + + // TODO: see BroadcastMovementUpdate; RelativeMove packet jerkiness affects projectiles too (cause of sympton described in cArrowEntity::Tick()) + if (GetProjectileKind() != pkArrow) { BroadcastMovementUpdate(); } @@ -335,19 +342,10 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) return; } - Vector3d PerTickSpeed = GetSpeed() / 20; - Vector3d Pos = GetPosition(); - - // Trace the tick's worth of movement as a line: - Vector3d NextPos = Pos + PerTickSpeed; - cProjectileTracerCallback TracerCallback(this); - if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos)) - { - // Something has been hit, abort all other processing - return; - } - // The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff - + const Vector3d PerTickSpeed = GetSpeed() / 20; + const Vector3d Pos = GetPosition(); + const Vector3d NextPos = Pos + PerTickSpeed; + // Test for entity collisions: cProjectileEntityCollisionCallback EntityCollisionCallback(this, Pos, NextPos); a_Chunk.ForEachEntity(EntityCollisionCallback); @@ -363,11 +361,20 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) EntityCollisionCallback.GetHitEntity()->GetClass(), HitPos.x, HitPos.y, HitPos.z, EntityCollisionCallback.GetMinCoeff() - ); - + ); + OnHitEntity(*(EntityCollisionCallback.GetHitEntity()), HitPos); } // TODO: Test the entities in the neighboring chunks, too + + // Trace the tick's worth of movement as a line: + cProjectileTracerCallback TracerCallback(this); + if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos)) + { + // Something has been hit, abort all other processing + return; + } + // The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff // Update the position: SetPosition(NextPos); diff --git a/src/Entities/ThrownEggEntity.cpp b/src/Entities/ThrownEggEntity.cpp index 224019091..d7eed41e3 100644 --- a/src/Entities/ThrownEggEntity.cpp +++ b/src/Entities/ThrownEggEntity.cpp @@ -8,7 +8,8 @@ cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) + super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25), + m_DestroyTimer(-1) { SetSpeed(a_Speed); } @@ -21,7 +22,7 @@ void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_H { TrySpawnChicken(a_HitPos); - Destroy(); + m_DestroyTimer = 5; } @@ -36,7 +37,7 @@ void cThrownEggEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_Hit TrySpawnChicken(a_HitPos); a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); - Destroy(true); + m_DestroyTimer = 5; } diff --git a/src/Entities/ThrownEggEntity.h b/src/Entities/ThrownEggEntity.h index 5ba8f051b..894665428 100644 --- a/src/Entities/ThrownEggEntity.h +++ b/src/Entities/ThrownEggEntity.h @@ -30,8 +30,26 @@ protected: // cProjectileEntity overrides: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + virtual void Tick (float a_Dt, cChunk & a_Chunk) override + { + if (m_DestroyTimer > 0) + { + m_DestroyTimer--; + if (m_DestroyTimer == 0) + { + Destroy(); + return; + } + } + else { super::Tick(a_Dt, a_Chunk); } + } // Randomly decides whether to spawn a chicken where the egg lands. void TrySpawnChicken(const Vector3d & a_HitPos); + +private: + + /** Time in ticks to wait for the hit animation to begin before destroying */ + int m_DestroyTimer; } ; // tolua_export diff --git a/src/Entities/ThrownEnderPearlEntity.cpp b/src/Entities/ThrownEnderPearlEntity.cpp index c37161145..a3ee23389 100644 --- a/src/Entities/ThrownEnderPearlEntity.cpp +++ b/src/Entities/ThrownEnderPearlEntity.cpp @@ -7,7 +7,8 @@ cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) + super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25), + m_DestroyTimer(-1) { SetSpeed(a_Speed); } @@ -21,7 +22,7 @@ void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockF // TODO: Tweak a_HitPos based on block face. TeleportCreator(a_HitPos); - Destroy(); + m_DestroyTimer = 5; } @@ -36,7 +37,7 @@ void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d TeleportCreator(a_HitPos); a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); - Destroy(true); + m_DestroyTimer = 5; } @@ -48,7 +49,7 @@ void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos) // Teleport the creator here, make them take 5 damage: if (m_Creator != NULL) { - m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5); + m_Creator->TeleportToCoords(a_HitPos.x, a_HitPos.y + 0.2, a_HitPos.z); m_Creator->TakeDamage(dtEnderPearl, this, 5, 0); } } diff --git a/src/Entities/ThrownEnderPearlEntity.h b/src/Entities/ThrownEnderPearlEntity.h index ddee5babe..bfd9bd70d 100644 --- a/src/Entities/ThrownEnderPearlEntity.h +++ b/src/Entities/ThrownEnderPearlEntity.h @@ -30,8 +30,26 @@ protected: // cProjectileEntity overrides: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; - - // Teleports the creator where the ender pearl lands. + virtual void Tick (float a_Dt, cChunk & a_Chunk) override + { + if (m_DestroyTimer > 0) + { + m_DestroyTimer--; + if (m_DestroyTimer == 0) + { + Destroy(); + return; + } + } + else { super::Tick(a_Dt, a_Chunk); } + } + + /** Teleports the creator where the ender pearl lands */ void TeleportCreator(const Vector3d & a_HitPos); + +private: + + /** Time in ticks to wait for the hit animation to begin before destroying */ + int m_DestroyTimer; } ; // tolua_export diff --git a/src/Entities/ThrownSnowballEntity.cpp b/src/Entities/ThrownSnowballEntity.cpp index cefc3433c..b82cd56db 100644 --- a/src/Entities/ThrownSnowballEntity.cpp +++ b/src/Entities/ThrownSnowballEntity.cpp @@ -8,7 +8,8 @@ cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) + super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25), + m_DestroyTimer(-1) { SetSpeed(a_Speed); } @@ -19,7 +20,7 @@ cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, do void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) { - Destroy(); + m_DestroyTimer = 5; } @@ -40,5 +41,5 @@ void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & // TODO: If entity is Ender Crystal, destroy it a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); - Destroy(true); + m_DestroyTimer = 5; } diff --git a/src/Entities/ThrownSnowballEntity.h b/src/Entities/ThrownSnowballEntity.h index a09512e37..e30971f0a 100644 --- a/src/Entities/ThrownSnowballEntity.h +++ b/src/Entities/ThrownSnowballEntity.h @@ -30,5 +30,23 @@ protected: // cProjectileEntity overrides: virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + virtual void Tick (float a_Dt, cChunk & a_Chunk) override + { + if (m_DestroyTimer > 0) + { + m_DestroyTimer--; + if (m_DestroyTimer == 0) + { + Destroy(); + return; + } + } + else { super::Tick(a_Dt, a_Chunk); } + } + +private: + + /** Time in ticks to wait for the hit animation to begin before destroying */ + int m_DestroyTimer; } ; // tolua_export -- cgit v1.2.3 From 4238b0ebe8d910186d4e160222f337b6e8b33cc8 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 22 Jun 2014 20:44:18 +0100 Subject: Some Entity.cpp style improvements --- src/Entities/Entity.cpp | 17 ++++++----------- src/Entities/Entity.h | 4 ++-- 2 files changed, 8 insertions(+), 13 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index ee7ce06ac..f4e89367b 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -255,8 +255,7 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R void cEntity::SetYawFromSpeed(void) { - const double EPS = 0.0000001; - if ((abs(m_Speed.x) < EPS) && (abs(m_Speed.z) < EPS)) + if ((abs(m_Speed.x) < std::numeric_limits::epsilon()) && (abs(m_Speed.z) < std::numeric_limits::epsilon())) { // atan2() may overflow or is undefined, pick any number SetYaw(0); @@ -1236,7 +1235,7 @@ void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude) if (GetWorld()->GetWorldAge() % 2 == 0) { double SpeedSqr = GetSpeed().SqrLength(); - if (SpeedSqr == 0.0) + if (SpeedSqr < std::numeric_limits::epsilon()) { // Speed is zero, send this to clients once only as well as an absolute position if (!m_bHasSentNoSpeed) @@ -1476,8 +1475,7 @@ void cEntity::SetWidth(double a_Width) void cEntity::AddPosX(double a_AddPosX) { - m_Pos.x += a_AddPosX; - + m_Pos.x += a_AddPosX; } @@ -1485,8 +1483,7 @@ void cEntity::AddPosX(double a_AddPosX) void cEntity::AddPosY(double a_AddPosY) { - m_Pos.y += a_AddPosY; - + m_Pos.y += a_AddPosY; } @@ -1494,8 +1491,7 @@ void cEntity::AddPosY(double a_AddPosY) void cEntity::AddPosZ(double a_AddPosZ) { - m_Pos.z += a_AddPosZ; - + m_Pos.z += a_AddPosZ; } @@ -1505,8 +1501,7 @@ void cEntity::AddPosition(double a_AddPosX, double a_AddPosY, double a_AddPosZ) { m_Pos.x += a_AddPosX; m_Pos.y += a_AddPosY; - m_Pos.z += a_AddPosZ; - + m_Pos.z += a_AddPosZ; } diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 2df66e353..f4080f8aa 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -237,9 +237,9 @@ public: void AddPosY (double a_AddPosY); void AddPosZ (double a_AddPosZ); void AddPosition(double a_AddPosX, double a_AddPosY, double a_AddPosZ); - void AddPosition(const Vector3d & a_AddPos) { AddPosition(a_AddPos.x,a_AddPos.y,a_AddPos.z);} + void AddPosition(const Vector3d & a_AddPos) { AddPosition(a_AddPos.x, a_AddPos.y, a_AddPos.z); } void AddSpeed (double a_AddSpeedX, double a_AddSpeedY, double a_AddSpeedZ); - void AddSpeed (const Vector3d & a_AddSpeed) { AddSpeed(a_AddSpeed.x,a_AddSpeed.y,a_AddSpeed.z);} + void AddSpeed (const Vector3d & a_AddSpeed) { AddSpeed(a_AddSpeed.x, a_AddSpeed.y, a_AddSpeed.z); } void AddSpeedX (double a_AddSpeedX); void AddSpeedY (double a_AddSpeedY); void AddSpeedZ (double a_AddSpeedZ); -- cgit v1.2.3 From b6df30831d6b9b84bbb231dd8cfe4c1532666da4 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 27 Jun 2014 23:13:26 +0100 Subject: Fixed server forcing players afloat * Fixes #1131 --- src/Entities/Entity.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/Entities') diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index ee7ce06ac..2b256e766 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1090,7 +1090,10 @@ void cEntity::HandleAir(void) if (IsSubmerged()) { - SetSpeedY(1); // Float in the water + if (!IsPlayer()) // Players control themselves + { + SetSpeedY(1); // Float in the water + } // Either reduce air level or damage player if (m_AirLevel < 1) -- cgit v1.2.3 From 35dc056f0350c5fda178d0c28230f0a6b0feabbc Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 28 Jun 2014 21:10:59 +0100 Subject: Likely fixed too quick food depletion * Fixes FS427 properly, hopefully --- src/Entities/Player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 7b4fd219d..0abe50d11 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1913,7 +1913,7 @@ void cPlayer::HandleFood(void) { m_FoodTickTimer = 0; - if (m_FoodLevel >= 17) + if ((m_FoodLevel > 17) && (GetHealth() < GetMaxHealth())) { // Regenerate health from food, incur 3 pts of food exhaustion: Heal(1); -- cgit v1.2.3 From 536cb62f1c4ee47bf39a04240f9460953f3f8869 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 28 Jun 2014 21:14:10 +0100 Subject: An unification of code style --- src/Entities/ProjectileEntity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Entities') diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index d45f1d212..76daca186 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -361,7 +361,7 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) EntityCollisionCallback.GetHitEntity()->GetClass(), HitPos.x, HitPos.y, HitPos.z, EntityCollisionCallback.GetMinCoeff() - ); + ); OnHitEntity(*(EntityCollisionCallback.GetHitEntity()), HitPos); } -- cgit v1.2.3 From dde641ce83de474187102f0efbbced826673f54d Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 29 Jun 2014 11:36:38 +0100 Subject: Properly implemented enderchests --- src/Entities/Player.cpp | 7 +++++++ src/Entities/Player.h | 11 +++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 0abe50d11..aeeea3d07 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -8,6 +8,7 @@ #include "../World.h" #include "../Bindings/PluginManager.h" #include "../BlockEntities/BlockEntity.h" +#include "../BlockEntities/EnderChestEntity.h" #include "../GroupManager.h" #include "../Group.h" #include "../Root.h" @@ -46,6 +47,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) , m_bTouchGround(false) , m_Stance(0.0) , m_Inventory(*this) + , m_EnderChestContents(9, 3) , m_CurrentWindow(NULL) , m_InventoryWindow(NULL) , m_Color('-') @@ -1743,6 +1745,7 @@ bool cPlayer::LoadFromDisk() } m_Inventory.LoadFromJson(root["inventory"]); + cEnderChestEntity::LoadFromJson(root["enderchestinventory"], m_EnderChestContents); m_LoadedWorldName = root.get("world", "world").asString(); @@ -1780,10 +1783,14 @@ bool cPlayer::SaveToDisk() Json::Value JSON_Inventory; m_Inventory.SaveToJson(JSON_Inventory); + Json::Value JSON_EnderChestInventory; + cEnderChestEntity::SaveToJson(JSON_EnderChestInventory, m_EnderChestContents); + Json::Value root; root["position"] = JSON_PlayerPosition; root["rotation"] = JSON_PlayerRotation; root["inventory"] = JSON_Inventory; + root["enderchestinventory"] = JSON_EnderChestInventory; root["health"] = m_Health; root["xpTotal"] = m_LifetimeTotalXp; root["xpCurrent"] = m_CurrentXp; diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 2f7957f16..c70733c8c 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -124,6 +124,9 @@ public: inline double GetStance(void) const { return GetPosY() + 1.62; } // tolua_export // TODO: Proper stance when crouching etc. inline cInventory & GetInventory(void) { return m_Inventory; } // tolua_export inline const cInventory & GetInventory(void) const { return m_Inventory; } + + /** Gets the contents of the player's associated enderchest */ + cItemGrid & GetEnderChestContents(void) { return m_EnderChestContents; } inline const cItem & GetEquippedItem(void) const { return GetInventory().GetEquippedItem(); } // tolua_export @@ -449,7 +452,13 @@ protected: float m_LastGroundHeight; bool m_bTouchGround; double m_Stance; + + /** Stores the player's inventory, consisting of crafting grid, hotbar, and main slots */ cInventory m_Inventory; + + /** An item grid that stores the player specific enderchest contents */ + cItemGrid m_EnderChestContents; + cWindow * m_CurrentWindow; cWindow * m_InventoryWindow; @@ -510,8 +519,6 @@ protected: cStatManager m_Stats; - - /** Sets the speed and sends it to the client, so that they are forced to move so. */ virtual void DoSetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ) override; -- cgit v1.2.3 From 428cfb5c21ec5a35252b967eb306d6ba9b8e11b3 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 29 Jun 2014 22:41:31 +0100 Subject: Suggestions --- src/Entities/ArrowEntity.cpp | 4 +++- src/Entities/Entity.cpp | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index db9dc781a..c76c710ef 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -69,7 +69,9 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) { Vector3d Hit = a_HitPos; - Hit += GetSpeed() / 700; // Make arrow sink into block a little + Vector3d SinkMovement = GetSpeed() / 800; + SinkMovement.Clamp(0.001, 0.001, 0.001, 0.05, 0.05, 0.05); + Hit += SinkMovement; // Make arrow sink into block a little super::OnHitSolidBlock(Hit, a_HitFace); int X = (int)floor(Hit.x), Y = (int)floor(Hit.y), Z = (int)floor(Hit.z); diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index f4e89367b..1683aa209 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -255,7 +255,8 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R void cEntity::SetYawFromSpeed(void) { - if ((abs(m_Speed.x) < std::numeric_limits::epsilon()) && (abs(m_Speed.z) < std::numeric_limits::epsilon())) + const double EPS = 0.0000001; + if ((abs(m_Speed.x) < EPS) && (abs(m_Speed.z) < EPS)) { // atan2() may overflow or is undefined, pick any number SetYaw(0); @@ -1235,7 +1236,7 @@ void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude) if (GetWorld()->GetWorldAge() % 2 == 0) { double SpeedSqr = GetSpeed().SqrLength(); - if (SpeedSqr < std::numeric_limits::epsilon()) + if (SpeedSqr == 0.0) { // Speed is zero, send this to clients once only as well as an absolute position if (!m_bHasSentNoSpeed) -- cgit v1.2.3 From b9d4431f6f2b60802d66da03f0b915bbd2c846cb Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 29 Jun 2014 22:44:01 +0100 Subject: Fixed respawning * Fixes #1103 --- src/Entities/Player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 0abe50d11..daf1ef2cc 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -976,7 +976,7 @@ void cPlayer::Respawn(void) m_LifetimeTotalXp = 0; // ToDo: send score to client? How? - m_ClientHandle->SendRespawn(*m_World); + m_ClientHandle->SendRespawn(*m_World, true); // Extinguish the fire: StopBurning(); -- cgit v1.2.3 From aa753a92c092a4d35b2ff7d08259c3196abecf67 Mon Sep 17 00:00:00 2001 From: Howaner Date: Mon, 30 Jun 2014 15:12:56 +0200 Subject: Add new hook: HOOK_PLAYER_FOOD_LEVEL_CHANGE --- src/Entities/Player.cpp | 50 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index daf1ef2cc..ed18d2ab7 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -37,9 +37,9 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) : super(etPlayer, 0.6, 1.8) , m_bVisible(true) , m_FoodLevel(MAX_FOOD_LEVEL) - , m_FoodSaturationLevel(5) + , m_FoodSaturationLevel(5.0) , m_FoodTickTimer(0) - , m_FoodExhaustionLevel(0) + , m_FoodExhaustionLevel(0.0) , m_FoodPoisonedTicksRemaining(0) , m_LastJumpHeight(0) , m_LastGroundHeight(0) @@ -521,7 +521,15 @@ void cPlayer::Heal(int a_Health) void cPlayer::SetFoodLevel(int a_FoodLevel) { - m_FoodLevel = std::max(0, std::min(a_FoodLevel, (int)MAX_FOOD_LEVEL)); + a_FoodLevel = std::max(0, std::min(a_FoodLevel, (int)MAX_FOOD_LEVEL)); + + if (cRoot::Get()->GetPluginManager()->CallHookPlayerFoodLevelChange(*this, a_FoodLevel)) + { + m_FoodSaturationLevel = 5.0; + return; + } + + m_FoodLevel = a_FoodLevel; SendHealth(); } @@ -571,11 +579,9 @@ bool cPlayer::Feed(int a_Food, double a_Saturation) { return false; } - - m_FoodLevel = std::min(a_Food + m_FoodLevel, (int)MAX_FOOD_LEVEL); - m_FoodSaturationLevel = std::min(m_FoodSaturationLevel + a_Saturation, (double)m_FoodLevel); - - SendHealth(); + + SetFoodSaturationLevel(m_FoodSaturationLevel + a_Saturation); + SetFoodLevel(m_FoodLevel + a_Food); return true; } @@ -969,7 +975,7 @@ void cPlayer::Respawn(void) // Reset food level: m_FoodLevel = MAX_FOOD_LEVEL; - m_FoodSaturationLevel = 5; + m_FoodSaturationLevel = 5.0; // Reset Experience m_CurrentXp = 0; @@ -1895,16 +1901,13 @@ void cPlayer::TickBurning(cChunk & a_Chunk) void cPlayer::HandleFood(void) { // Ref.: http://www.minecraftwiki.net/wiki/Hunger - + if (IsGameModeCreative()) { // Hunger is disabled for Creative return; } - - // Remember the food level before processing, for later comparison - int LastFoodLevel = m_FoodLevel; - + // Heal or damage, based on the food level, using the m_FoodTickTimer: if ((m_FoodLevel > 17) || (m_FoodLevel <= 0)) { @@ -1917,7 +1920,7 @@ void cPlayer::HandleFood(void) { // Regenerate health from food, incur 3 pts of food exhaustion: Heal(1); - m_FoodExhaustionLevel += 3; + m_FoodExhaustionLevel += 3.0; } else if ((m_FoodLevel <= 0) && (m_Health > 1)) { @@ -1926,7 +1929,7 @@ void cPlayer::HandleFood(void) } } } - + // Apply food poisoning food exhaustion: if (m_FoodPoisonedTicksRemaining > 0) { @@ -1939,24 +1942,19 @@ void cPlayer::HandleFood(void) } // Apply food exhaustion that has accumulated: - if (m_FoodExhaustionLevel >= 4) + if (m_FoodExhaustionLevel >= 4.0) { - m_FoodExhaustionLevel -= 4; + m_FoodExhaustionLevel -= 4.0; - if (m_FoodSaturationLevel >= 1) + if (m_FoodSaturationLevel >= 1.0) { - m_FoodSaturationLevel -= 1; + m_FoodSaturationLevel -= 1.0; } else { - m_FoodLevel = std::max(m_FoodLevel - 1, 0); + SetFoodLevel(m_FoodLevel - 1); } } - - if (m_FoodLevel != LastFoodLevel) - { - SendHealth(); - } } -- cgit v1.2.3 From 85fae0e521d3a2ea4f083ee2bc54ac7fbb357768 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Mon, 30 Jun 2014 19:21:21 +0100 Subject: Implemented Vector3<>::Floor() --- src/Entities/ArrowEntity.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index c76c710ef..2d6683f0a 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -74,8 +74,9 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFa Hit += SinkMovement; // Make arrow sink into block a little super::OnHitSolidBlock(Hit, a_HitFace); - int X = (int)floor(Hit.x), Y = (int)floor(Hit.y), Z = (int)floor(Hit.z); - + Hit.Floor(); + + int X = Hit.x, Y = Hit.y, Z = Hit.z; m_HitBlockPos = Vector3i(X, Y, Z); // Broadcast arrow hit sound -- cgit v1.2.3 From 8e11f7a1f64fd4d20495f1a4467ef168d18db92b Mon Sep 17 00:00:00 2001 From: Howaner Date: Mon, 30 Jun 2014 21:50:40 +0200 Subject: Fixes. --- src/Entities/Player.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index ed18d2ab7..ab2dbc0cf 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -521,15 +521,15 @@ void cPlayer::Heal(int a_Health) void cPlayer::SetFoodLevel(int a_FoodLevel) { - a_FoodLevel = std::max(0, std::min(a_FoodLevel, (int)MAX_FOOD_LEVEL)); + int FoodLevel = std::max(0, std::min(a_FoodLevel, (int)MAX_FOOD_LEVEL)); - if (cRoot::Get()->GetPluginManager()->CallHookPlayerFoodLevelChange(*this, a_FoodLevel)) + if (cRoot::Get()->GetPluginManager()->CallHookPlayerFoodLevelChange(*this, FoodLevel)) { m_FoodSaturationLevel = 5.0; return; } - m_FoodLevel = a_FoodLevel; + m_FoodLevel = FoodLevel; SendHealth(); } -- cgit v1.2.3 From 284c1c0514168e30338f2ad372b7e7f185dba0c4 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Tue, 1 Jul 2014 22:39:37 +0100 Subject: Vector clamping fixes Thank you, @madmaxoft. --- src/Entities/ArrowEntity.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index 2d6683f0a..7e96a666d 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -69,14 +69,18 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) { Vector3d Hit = a_HitPos; - Vector3d SinkMovement = GetSpeed() / 800; - SinkMovement.Clamp(0.001, 0.001, 0.001, 0.05, 0.05, 0.05); + Vector3d SinkMovement = GetSpeed() / 800; // Base value for arrow penetration + SinkMovement = Clamp( // Adjust the movement so that fast arrows don't go through blocks (though in reality they would, in addition to exploding into fragments :P) + SinkMovement, + (SinkMovement * 0.001) / SinkMovement.Length(), + (SinkMovement * 0.05) / SinkMovement.Length() + ); Hit += SinkMovement; // Make arrow sink into block a little super::OnHitSolidBlock(Hit, a_HitFace); - Hit.Floor(); + Vector3i BlockHit = Hit.Floor(); - int X = Hit.x, Y = Hit.y, Z = Hit.z; + int X = BlockHit.x, Y = BlockHit.y, Z = BlockHit.z; m_HitBlockPos = Vector3i(X, Y, Z); // Broadcast arrow hit sound -- cgit v1.2.3 From c1ae5513ec9e9cc3aac641b793a77f3ef4c14bda Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 2 Jul 2014 18:46:13 +0100 Subject: Fixed player teleport food drain --- src/Entities/Player.cpp | 10 +++++++++- src/Entities/Player.h | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index daf1ef2cc..66791eb7c 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -71,6 +71,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) , m_FloaterID(-1) , m_Team(NULL) , m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL) + , m_bIsTeleporting(false) { LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d", a_PlayerName.c_str(), a_Client->GetIPString().c_str(), @@ -225,7 +226,7 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) SendExperience(); } - if (GetPosition() != m_LastPos) // Change in position from last tick? + if (!GetPosition().EqualsEps(m_LastPos, 0.01)) // Non negligible change in position from last tick? { // Apply food exhaustion from movement: ApplyFoodExhaustionFromMovement(); @@ -970,6 +971,7 @@ void cPlayer::Respawn(void) // Reset food level: m_FoodLevel = MAX_FOOD_LEVEL; m_FoodSaturationLevel = 5; + m_FoodExhaustionLevel = 0; // Reset Experience m_CurrentXp = 0; @@ -1226,6 +1228,7 @@ void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) SetPosition(a_PosX, a_PosY, a_PosZ); m_LastGroundHeight = (float)a_PosY; m_LastJumpHeight = (float)a_PosY; + m_bIsTeleporting = true; m_World->BroadcastTeleportEntity(*this, GetClientHandle()); m_ClientHandle->SendPlayerMoveLook(); @@ -2079,6 +2082,11 @@ void cPlayer::ApplyFoodExhaustionFromMovement() { return; } + if (m_bIsTeleporting) + { + m_bIsTeleporting = false; + return; + } // If riding anything, apply no food exhaustion if (m_AttachedTo != NULL) diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 2f7957f16..9e443b468 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -546,6 +546,11 @@ protected: Default save interval is #defined in PLAYER_INVENTORY_SAVE_INTERVAL */ unsigned int m_TicksUntilNextSave; + /** Flag used by food handling system to determine whether a teleport has just happened + Will not apply food penalties if found to be true; will set to false after processing + */ + bool m_bIsTeleporting; + } ; // tolua_export -- cgit v1.2.3 From abb49d3f338de4078177d1b95e3ed8d195119b50 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 2 Jul 2014 18:51:37 +0100 Subject: Suggestion --- src/Entities/Player.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index aeeea3d07..f888af642 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1787,20 +1787,20 @@ bool cPlayer::SaveToDisk() cEnderChestEntity::SaveToJson(JSON_EnderChestInventory, m_EnderChestContents); Json::Value root; - root["position"] = JSON_PlayerPosition; - root["rotation"] = JSON_PlayerRotation; - root["inventory"] = JSON_Inventory; + root["position"] = JSON_PlayerPosition; + root["rotation"] = JSON_PlayerRotation; + root["inventory"] = JSON_Inventory; root["enderchestinventory"] = JSON_EnderChestInventory; - root["health"] = m_Health; - root["xpTotal"] = m_LifetimeTotalXp; - root["xpCurrent"] = m_CurrentXp; - root["air"] = m_AirLevel; - root["food"] = m_FoodLevel; - root["foodSaturation"] = m_FoodSaturationLevel; - root["foodTickTimer"] = m_FoodTickTimer; - root["foodExhaustion"] = m_FoodExhaustionLevel; - root["world"] = GetWorld()->GetName(); - root["isflying"] = IsFlying(); + root["health"] = m_Health; + root["xpTotal"] = m_LifetimeTotalXp; + root["xpCurrent"] = m_CurrentXp; + root["air"] = m_AirLevel; + root["food"] = m_FoodLevel; + root["foodSaturation"] = m_FoodSaturationLevel; + root["foodTickTimer"] = m_FoodTickTimer; + root["foodExhaustion"] = m_FoodExhaustionLevel; + root["world"] = GetWorld()->GetName(); + root["isflying"] = IsFlying(); if (m_GameMode == GetWorld()->GetGameMode()) { -- cgit v1.2.3 From 89a26cc786f3673cf7b5a100300d8aa595735cc3 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 2 Jul 2014 21:07:34 +0100 Subject: Suggestions --- src/Entities/ArrowEntity.cpp | 16 ++++++++-------- src/Entities/ArrowEntity.h | 6 ++++++ 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index 7e96a666d..c039b0b3c 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -67,15 +67,15 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) -{ +{ + if (GetSpeed().SqrLength() == 0) + { + SetSpeed(GetLookVector().NormalizeCopy() * 0.1); // Ensure that no division by zero happens later + } + Vector3d Hit = a_HitPos; - Vector3d SinkMovement = GetSpeed() / 800; // Base value for arrow penetration - SinkMovement = Clamp( // Adjust the movement so that fast arrows don't go through blocks (though in reality they would, in addition to exploding into fragments :P) - SinkMovement, - (SinkMovement * 0.001) / SinkMovement.Length(), - (SinkMovement * 0.05) / SinkMovement.Length() - ); - Hit += SinkMovement; // Make arrow sink into block a little + Vector3d SinkMovement = (GetSpeed() / 800); + Hit += (SinkMovement * 0.01) / SinkMovement.Length(); // Make arrow sink into block a centimetre so it lodges (but not to far so it goes black clientside) super::OnHitSolidBlock(Hit, a_HitFace); Vector3i BlockHit = Hit.Floor(); diff --git a/src/Entities/ArrowEntity.h b/src/Entities/ArrowEntity.h index 1fe3032ee..99b7bae31 100644 --- a/src/Entities/ArrowEntity.h +++ b/src/Entities/ArrowEntity.h @@ -58,8 +58,14 @@ public: /// Sets the IsCritical flag void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; } + + /** Gets the block arrow is in */ + Vector3i GetBlockHit(void) const { return m_HitBlockPos; } // tolua_end + + /** Sets the block arrow is in */ + void SetBlockHit(const Vector3i & a_BlockHit) { m_HitBlockPos = a_BlockHit; } protected: -- cgit v1.2.3 From f6350662414044896e7971dcc792c83d5eaddbce Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 4 Jul 2014 12:50:40 +0100 Subject: Eps comparison --- src/Entities/ArrowEntity.cpp | 2 +- src/Entities/ArrowEntity.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index c039b0b3c..1d539679c 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -68,7 +68,7 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) { - if (GetSpeed().SqrLength() == 0) + if (GetSpeed().EqualsEps(Vector3d(0, 0, 0), 0.0000001)) { SetSpeed(GetLookVector().NormalizeCopy() * 0.1); // Ensure that no division by zero happens later } diff --git a/src/Entities/ArrowEntity.h b/src/Entities/ArrowEntity.h index 99b7bae31..76cb24449 100644 --- a/src/Entities/ArrowEntity.h +++ b/src/Entities/ArrowEntity.h @@ -64,7 +64,7 @@ public: // tolua_end - /** Sets the block arrow is in */ + /** Sets the block arrow is in. To be used by the MCA loader only! */ void SetBlockHit(const Vector3i & a_BlockHit) { m_HitBlockPos = a_BlockHit; } protected: -- cgit v1.2.3 From f4e3c01a710a2cc5118807a65f8d27519a19ef37 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 4 Jul 2014 16:49:24 +0100 Subject: 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 ++-- 3 files changed, 107 insertions(+), 10 deletions(-) (limited to 'src/Entities') 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); } } -- cgit v1.2.3 From 79e558be349c40ed40b5eefefd29f563a570e404 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 4 Jul 2014 17:42:40 +0100 Subject: Suggestions --- src/Entities/ThrownEggEntity.cpp | 2 +- src/Entities/ThrownEggEntity.h | 5 ++++- src/Entities/ThrownEnderPearlEntity.cpp | 2 +- src/Entities/ThrownEnderPearlEntity.h | 5 ++++- src/Entities/ThrownSnowballEntity.cpp | 2 +- src/Entities/ThrownSnowballEntity.h | 5 ++++- 6 files changed, 15 insertions(+), 6 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/ThrownEggEntity.cpp b/src/Entities/ThrownEggEntity.cpp index d7eed41e3..456083108 100644 --- a/src/Entities/ThrownEggEntity.cpp +++ b/src/Entities/ThrownEggEntity.cpp @@ -22,7 +22,7 @@ void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_H { TrySpawnChicken(a_HitPos); - m_DestroyTimer = 5; + m_DestroyTimer = 2; } diff --git a/src/Entities/ThrownEggEntity.h b/src/Entities/ThrownEggEntity.h index 894665428..dc72c279f 100644 --- a/src/Entities/ThrownEggEntity.h +++ b/src/Entities/ThrownEggEntity.h @@ -41,7 +41,10 @@ protected: return; } } - else { super::Tick(a_Dt, a_Chunk); } + else + { + super::Tick(a_Dt, a_Chunk); + } } // Randomly decides whether to spawn a chicken where the egg lands. diff --git a/src/Entities/ThrownEnderPearlEntity.cpp b/src/Entities/ThrownEnderPearlEntity.cpp index 96dd41ee6..aeb727205 100644 --- a/src/Entities/ThrownEnderPearlEntity.cpp +++ b/src/Entities/ThrownEnderPearlEntity.cpp @@ -22,7 +22,7 @@ void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockF // TODO: Tweak a_HitPos based on block face. TeleportCreator(a_HitPos); - m_DestroyTimer = 5; + m_DestroyTimer = 2; } diff --git a/src/Entities/ThrownEnderPearlEntity.h b/src/Entities/ThrownEnderPearlEntity.h index bfd9bd70d..1cea5f7d9 100644 --- a/src/Entities/ThrownEnderPearlEntity.h +++ b/src/Entities/ThrownEnderPearlEntity.h @@ -41,7 +41,10 @@ protected: return; } } - else { super::Tick(a_Dt, a_Chunk); } + else + { + super::Tick(a_Dt, a_Chunk); + } } /** Teleports the creator where the ender pearl lands */ diff --git a/src/Entities/ThrownSnowballEntity.cpp b/src/Entities/ThrownSnowballEntity.cpp index b82cd56db..d94e75898 100644 --- a/src/Entities/ThrownSnowballEntity.cpp +++ b/src/Entities/ThrownSnowballEntity.cpp @@ -20,7 +20,7 @@ cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, do void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) { - m_DestroyTimer = 5; + m_DestroyTimer = 2; } diff --git a/src/Entities/ThrownSnowballEntity.h b/src/Entities/ThrownSnowballEntity.h index e30971f0a..9a8770379 100644 --- a/src/Entities/ThrownSnowballEntity.h +++ b/src/Entities/ThrownSnowballEntity.h @@ -41,7 +41,10 @@ protected: return; } } - else { super::Tick(a_Dt, a_Chunk); } + else + { + super::Tick(a_Dt, a_Chunk); + } } private: -- cgit v1.2.3 From f4e11d194e9e4a2e85a9f9688312ad08ade45b83 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 4 Jul 2014 22:07:26 +0100 Subject: Crash and compile fix --- src/Entities/ProjectileEntity.cpp | 11 ++++++++--- src/Entities/ProjectileEntity.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index ddcc0f7fd..50f62b018 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -216,7 +216,10 @@ 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_CreatorData(a_Creator->GetUniqueID(), a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : ""), + m_CreatorData( + ((a_Creator != NULL) ? a_Creator->GetUniqueID() : -1), + ((a_Creator != NULL) ? (a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : "") : "") + ), m_IsInGround(false) { } @@ -298,7 +301,7 @@ void cProjectileEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_ cEntity * cProjectileEntity::GetCreator() { - if (m_CreatorData.m_Name.empty()) + if (m_CreatorData.m_Name.empty() && (m_CreatorData.m_UniqueID >= 1)) { class cProjectileCreatorCallback : public cEntityCallback { @@ -328,7 +331,7 @@ cEntity * cProjectileEntity::GetCreator() GetWorld()->DoWithEntityByID(m_CreatorData.m_UniqueID, PCC); return PCC.GetEntity(); } - else + else if (!m_CreatorData.m_Name.empty()) { class cProjectileCreatorCallbackForPlayers : public cPlayerListCallback { @@ -358,6 +361,8 @@ cEntity * cProjectileEntity::GetCreator() GetWorld()->FindAndDoWithPlayer(m_CreatorData.m_Name, PCCFP); return PCCFP.GetEntity(); } + + return NULL; } diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h index e2ebe9f27..84eefb9ee 100644 --- a/src/Entities/ProjectileEntity.h +++ b/src/Entities/ProjectileEntity.h @@ -94,7 +94,7 @@ protected: */ struct CreatorData { - CreatorData(int a_UniqueID, AString & a_Name) : + CreatorData(int a_UniqueID, const AString & a_Name) : m_UniqueID(a_UniqueID), m_Name(a_Name) { -- cgit v1.2.3 From 460d6bd0cbb799a6e68f1bc264f55c3d89eb8206 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 5 Jul 2014 22:59:22 +0100 Subject: Changed everything to callbacks --- src/Entities/ProjectileEntity.cpp | 72 +-------------------------------- src/Entities/ProjectileEntity.h | 6 +-- src/Entities/ThrownEnderPearlEntity.cpp | 35 +++++++++++++--- 3 files changed, 33 insertions(+), 80 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index 50f62b018..334973833 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -142,7 +142,7 @@ public: { if ( (a_Entity == m_Projectile) || // Do not check collisions with self - (a_Entity == m_Projectile->GetCreator()) // Do not check whoever shot the projectile + (a_Entity->GetUniqueID() == m_Projectile->GetCreatorUniqueID()) // Do not check whoever shot the projectile ) { // TODO: Don't check creator only for the first 5 ticks @@ -299,76 +299,6 @@ void cProjectileEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_ -cEntity * cProjectileEntity::GetCreator() -{ - if (m_CreatorData.m_Name.empty() && (m_CreatorData.m_UniqueID >= 1)) - { - 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 if (!m_CreatorData.m_Name.empty()) - { - 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(); - } - - return NULL; -} - - - - - AString cProjectileEntity::GetMCAClassName(void) const { switch (m_ProjectileKind) diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h index 84eefb9ee..7b38169e2 100644 --- a/src/Entities/ProjectileEntity.h +++ b/src/Entities/ProjectileEntity.h @@ -66,10 +66,10 @@ public: /// Returns the kind of the projectile (fast class identification) eKind GetProjectileKind(void) const { return m_ProjectileKind; } - /** 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! + /** Returns the unique ID of the entity who created this projectile + May return an ID <0 */ - cEntity * GetCreator(void); + int GetCreatorUniqueID(void) { return m_CreatorData.m_UniqueID; } /** Returns the name of the player that created the projectile Will be empty for non-player creators diff --git a/src/Entities/ThrownEnderPearlEntity.cpp b/src/Entities/ThrownEnderPearlEntity.cpp index aeb727205..c7407e6ae 100644 --- a/src/Entities/ThrownEnderPearlEntity.cpp +++ b/src/Entities/ThrownEnderPearlEntity.cpp @@ -1,6 +1,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "ThrownEnderPearlEntity.h" +#include "Player.h" @@ -46,12 +47,34 @@ 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 (Creator != NULL) + if (m_CreatorData.m_Name.empty()) { - Creator->TeleportToCoords(a_HitPos.x, a_HitPos.y + 0.2, a_HitPos.z); - Creator->TakeDamage(dtEnderPearl, this, 5, 0); + return; } + + class cProjectileCreatorCallbackForPlayers : public cPlayerListCallback + { + public: + cProjectileCreatorCallbackForPlayers(cEntity * a_Attacker, Vector3i a_HitPos) : + m_Attacker(a_Attacker), + m_HitPos(a_HitPos) + { + } + + virtual bool Item(cPlayer * a_Entity) override + { + // Teleport the creator here, make them take 5 damage: + a_Entity->TeleportToCoords(m_HitPos.x, m_HitPos.y + 0.2, m_HitPos.z); + a_Entity->TakeDamage(dtEnderPearl, m_Attacker, 5, 0); + return true; + } + + private: + + cEntity * m_Attacker; + Vector3i m_HitPos; + }; + + cProjectileCreatorCallbackForPlayers PCCFP(this, a_HitPos); + GetWorld()->FindAndDoWithPlayer(m_CreatorData.m_Name, PCCFP); } -- cgit v1.2.3 From 9e44b0aae164f2456a452714f869cc9670732d8e Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 6 Jul 2014 23:50:22 +0100 Subject: Implemented trapped chests & others + Added trapped chests * Fixed a bunch of bugs in the redstone simulator concerning wires and repeaters * Other potential bugfixes --- src/Entities/ExpOrb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Entities') diff --git a/src/Entities/ExpOrb.h b/src/Entities/ExpOrb.h index e76274ac9..2cd4ef31f 100644 --- a/src/Entities/ExpOrb.h +++ b/src/Entities/ExpOrb.h @@ -11,7 +11,7 @@ class cExpOrb : public cEntity { - typedef cExpOrb super; + typedef cEntity super; public: // tolua_end -- cgit v1.2.3 From 7c7501abc5345ec4eddd030ab4649b05354002c3 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Mon, 7 Jul 2014 21:14:15 +0100 Subject: Added extra space before comments --- src/Entities/ProjectileEntity.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index 334973833..0bb34019e 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -69,15 +69,15 @@ protected: if (cBlockInfo::IsSolid(a_BlockType)) { // The projectile hit a solid block, calculate the exact hit coords: - cBoundingBox bb(a_BlockX, a_BlockX + 1, a_BlockY, a_BlockY + 1, a_BlockZ, a_BlockZ + 1); // Bounding box of the block hit - const Vector3d LineStart = m_Projectile->GetPosition(); // Start point for the imaginary line that goes through the block hit - const Vector3d LineEnd = LineStart + m_Projectile->GetSpeed(); // End point for the imaginary line that goes through the block hit - double LineCoeff = 0; // Used to calculate where along the line an intersection with the bounding box occurs - eBlockFace Face; // Face hit + cBoundingBox bb(a_BlockX, a_BlockX + 1, a_BlockY, a_BlockY + 1, a_BlockZ, a_BlockZ + 1); // Bounding box of the block hit + const Vector3d LineStart = m_Projectile->GetPosition(); // Start point for the imaginary line that goes through the block hit + const Vector3d LineEnd = LineStart + m_Projectile->GetSpeed(); // End point for the imaginary line that goes through the block hit + double LineCoeff = 0; // Used to calculate where along the line an intersection with the bounding box occurs + eBlockFace Face; // Face hit if (bb.CalcLineIntersection(LineStart, LineEnd, LineCoeff, Face)) { - Vector3d Intersection = LineStart + m_Projectile->GetSpeed() * LineCoeff; // Point where projectile goes into the hit block + Vector3d Intersection = LineStart + m_Projectile->GetSpeed() * LineCoeff; // Point where projectile goes into the hit block if (cPluginManager::Get()->CallHookProjectileHitBlock(*m_Projectile, a_BlockX, a_BlockY, a_BlockZ, Face, &Intersection)) { -- cgit v1.2.3 From 74b6b398e7e5a2384f398b7dceaf45716bc70b6f Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 9 Jul 2014 19:56:50 +0100 Subject: Fixed arrow collection animation * Fixed piston extension non-solidness --- src/Entities/ArrowEntity.cpp | 24 +++--------------------- src/Entities/Pickup.cpp | 2 +- 2 files changed, 4 insertions(+), 22 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index 47a0876fc..d59088e72 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -106,14 +106,7 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1); // Broadcast successful hit sound - m_World->BroadcastSoundEffect( - "random.successful_hit", - (int)std::floor(GetPosX() * 8.0), - (int)std::floor(GetPosY() * 8.0), - (int)std::floor(GetPosZ() * 8.0), - 0.5f, - 0.75f + ((float)((GetUniqueID() * 23) % 32)) / 64.0f - ); + GetWorld()->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); Destroy(); } @@ -136,21 +129,10 @@ void cArrowEntity::CollectedBy(cPlayer * a_Dest) return; } } - - // TODO: BroadcastCollectPickup needs a cPickup, which we don't have - // m_World->BroadcastCollectPickup(*this, *a_Dest); + GetWorld()->BroadcastCollectEntity(*this, *a_Dest); + GetWorld()->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); m_bIsCollected = true; - - cFastRandom Random; - m_World->BroadcastSoundEffect( - "random.pop", - (int)std::floor(GetPosX() * 8.0), - (int)std::floor(GetPosY() * 8), - (int)std::floor(GetPosZ() * 8), - 0.2F, - ((Random.NextFloat(1.0F) - Random.NextFloat(1.0F)) * 0.7F + 1.0F) * 2.0F - ); } } diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp index 10b6bbd5c..24fa591da 100644 --- a/src/Entities/Pickup.cpp +++ b/src/Entities/Pickup.cpp @@ -224,7 +224,7 @@ bool cPickup::CollectedBy(cPlayer * a_Dest) } m_Item.m_ItemCount -= NumAdded; - m_World->BroadcastCollectPickup(*this, *a_Dest); + m_World->BroadcastCollectEntity(*this, *a_Dest); // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) m_World->BroadcastSoundEffect("random.pop",(int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); if (m_Item.m_ItemCount <= 0) -- cgit v1.2.3 From 2bd486660ab4140c42da8f0f92304d64afc604e2 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 11 Jul 2014 00:06:05 +0200 Subject: Preparation for player UUID-based storage: LoadFromFile() --- src/Entities/Player.cpp | 54 ++++++++++++++++++++++++++++++------------------- src/Entities/Player.h | 9 +++++++++ 2 files changed, 42 insertions(+), 21 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index dbb8cd26c..2cd4d4b31 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -75,11 +75,6 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) , m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL) , m_bIsTeleporting(false) { - LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d", - a_PlayerName.c_str(), a_Client->GetIPString().c_str(), - this, GetUniqueID() - ); - m_InventoryWindow = new cInventoryWindow(*this); m_CurrentWindow = m_InventoryWindow; m_InventoryWindow->OpenedByPlayer(*this); @@ -1690,53 +1685,70 @@ void cPlayer::LoadPermissionsFromDisk() -bool cPlayer::LoadFromDisk() + +bool cPlayer::LoadFromDisk(void) { LoadPermissionsFromDisk(); AString SourceFile; - Printf(SourceFile, "players/%s.json", GetName().c_str() ); + Printf(SourceFile, "players/%s.json", GetName().c_str()); + + bool res = LoadFromFile(SourceFile); + if (res) + { + return true; + } +} + + + + +bool cPlayer::LoadFromFile(const AString & a_FileName) +{ + // Load the data from the file: cFile f; - if (!f.Open(SourceFile, cFile::fmRead)) + if (!f.Open(a_FileName, cFile::fmRead)) { // This is a new player whom we haven't seen yet, bail out, let them have the defaults return false; } - AString buffer; if (f.ReadRestOfFile(buffer) != f.GetSize()) { - LOGWARNING("Cannot read player data from file \"%s\"", SourceFile.c_str()); + LOGWARNING("Cannot read player data from file \"%s\"", a_FileName.c_str()); return false; } - f.Close(); //cool kids play nice + f.Close(); + // Parse the JSON format: Json::Value root; Json::Reader reader; if (!reader.parse(buffer, root, false)) { - LOGWARNING("Cannot parse player data in file \"%s\", player will be reset", SourceFile.c_str()); + LOGWARNING("Cannot parse player data in file \"%s\"", a_FileName.c_str()); + return false; } + // Load the player data: Json::Value & JSON_PlayerPosition = root["position"]; if (JSON_PlayerPosition.size() == 3) { - SetPosX(JSON_PlayerPosition[(unsigned int)0].asDouble()); - SetPosY(JSON_PlayerPosition[(unsigned int)1].asDouble()); - SetPosZ(JSON_PlayerPosition[(unsigned int)2].asDouble()); + SetPosX(JSON_PlayerPosition[(unsigned)0].asDouble()); + SetPosY(JSON_PlayerPosition[(unsigned)1].asDouble()); + SetPosZ(JSON_PlayerPosition[(unsigned)2].asDouble()); m_LastPos = GetPosition(); } Json::Value & JSON_PlayerRotation = root["rotation"]; if (JSON_PlayerRotation.size() == 3) { - SetYaw ((float)JSON_PlayerRotation[(unsigned int)0].asDouble()); - SetPitch ((float)JSON_PlayerRotation[(unsigned int)1].asDouble()); - SetRoll ((float)JSON_PlayerRotation[(unsigned int)2].asDouble()); + SetYaw ((float)JSON_PlayerRotation[(unsigned)0].asDouble()); + SetPitch ((float)JSON_PlayerRotation[(unsigned)1].asDouble()); + SetRoll ((float)JSON_PlayerRotation[(unsigned)2].asDouble()); } - m_Health = root.get("health", 0).asInt(); + m_Health = root.get("health", 0).asInt(); m_AirLevel = root.get("air", MAX_AIR_LEVEL).asInt(); m_FoodLevel = root.get("food", MAX_FOOD_LEVEL).asInt(); m_FoodSaturationLevel = root.get("foodSaturation", MAX_FOOD_LEVEL).asDouble(); @@ -1763,8 +1775,8 @@ bool cPlayer::LoadFromDisk() cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats); StatSerializer.Load(); - LOGD("Player \"%s\" was read from file, spawning at {%.2f, %.2f, %.2f} in world \"%s\"", - GetName().c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str() + LOGD("Player \"%s\" was read from file \"%s\", spawning at {%.2f, %.2f, %.2f} in world \"%s\"", + GetName().c_str(), a_FileName.c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str() ); return true; diff --git a/src/Entities/Player.h b/src/Entities/Player.h index f247ac2f9..7641b0c31 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -41,6 +41,7 @@ public: cPlayer(cClientHandle * a_Client, const AString & a_PlayerName); + virtual ~cPlayer(); virtual void SpawnOn(cClientHandle & a_Client) override; @@ -337,7 +338,15 @@ public: bool MoveToWorld(const char * a_WorldName); // tolua_export bool SaveToDisk(void); + + /** Loads the player data from the disk file. + Returns true on success, false on failure. */ bool LoadFromDisk(void); + + /** Loads the player data from the specified file. + Returns true on success, false on failure. */ + bool LoadFromFile(const AString & a_FileName); + void LoadPermissionsFromDisk(void); // tolua_export const AString & GetLoadedWorldName() { return m_LoadedWorldName; } -- cgit v1.2.3 From 6cea81e3833bafbf2916ab2a06edf31c0f9a536e Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 11 Jul 2014 00:06:58 +0200 Subject: Fixed a missing return value. --- src/Entities/Player.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 2cd4d4b31..5a459d421 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1698,6 +1698,8 @@ bool cPlayer::LoadFromDisk(void) { return true; } + + return false; } -- cgit v1.2.3 From ebea2b7efc1775de66e0c6b6ee66da6f9ad04422 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 11 Jul 2014 13:13:10 +0200 Subject: Player data filenames are based on UUID. --- src/Entities/Player.cpp | 165 ++++++++++++++++++++++++++++++++---------------- src/Entities/Player.h | 34 ++++++---- 2 files changed, 132 insertions(+), 67 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 5a459d421..4e1314209 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -34,46 +34,47 @@ -cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) - : super(etPlayer, 0.6, 1.8) - , m_bVisible(true) - , m_FoodLevel(MAX_FOOD_LEVEL) - , m_FoodSaturationLevel(5.0) - , m_FoodTickTimer(0) - , m_FoodExhaustionLevel(0.0) - , m_FoodPoisonedTicksRemaining(0) - , m_LastJumpHeight(0) - , m_LastGroundHeight(0) - , m_bTouchGround(false) - , m_Stance(0.0) - , m_Inventory(*this) - , m_EnderChestContents(9, 3) - , m_CurrentWindow(NULL) - , m_InventoryWindow(NULL) - , m_Color('-') - , m_GameMode(eGameMode_NotSet) - , m_IP("") - , m_ClientHandle(a_Client) - , m_NormalMaxSpeed(1.0) - , m_SprintingMaxSpeed(1.3) - , m_FlyingMaxSpeed(1.0) - , m_IsCrouched(false) - , m_IsSprinting(false) - , m_IsFlying(false) - , m_IsSwimming(false) - , m_IsSubmerged(false) - , m_IsFishing(false) - , m_CanFly(false) - , m_EatingFinishTick(-1) - , m_LifetimeTotalXp(0) - , m_CurrentXp(0) - , m_bDirtyExperience(false) - , m_IsChargingBow(false) - , m_BowCharge(0) - , m_FloaterID(-1) - , m_Team(NULL) - , m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL) - , m_bIsTeleporting(false) +cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) : + super(etPlayer, 0.6, 1.8), + m_bVisible(true), + m_FoodLevel(MAX_FOOD_LEVEL), + m_FoodSaturationLevel(5.0), + m_FoodTickTimer(0), + m_FoodExhaustionLevel(0.0), + m_FoodPoisonedTicksRemaining(0), + m_LastJumpHeight(0), + m_LastGroundHeight(0), + m_bTouchGround(false), + m_Stance(0.0), + m_Inventory(*this), + m_EnderChestContents(9, 3), + m_CurrentWindow(NULL), + m_InventoryWindow(NULL), + m_Color('-'), + m_GameMode(eGameMode_NotSet), + m_IP(""), + m_ClientHandle(a_Client), + m_NormalMaxSpeed(1.0), + m_SprintingMaxSpeed(1.3), + m_FlyingMaxSpeed(1.0), + m_IsCrouched(false), + m_IsSprinting(false), + m_IsFlying(false), + m_IsSwimming(false), + m_IsSubmerged(false), + m_IsFishing(false), + m_CanFly(false), + m_EatingFinishTick(-1), + m_LifetimeTotalXp(0), + m_CurrentXp(0), + m_bDirtyExperience(false), + m_IsChargingBow(false), + m_BowCharge(0), + m_FloaterID(-1), + m_Team(NULL), + m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL), + m_bIsTeleporting(false), + m_UUID((a_Client != NULL) ? a_Client->GetUUID() : "") { m_InventoryWindow = new cInventoryWindow(*this); m_CurrentWindow = m_InventoryWindow; @@ -1690,15 +1691,42 @@ bool cPlayer::LoadFromDisk(void) { LoadPermissionsFromDisk(); - AString SourceFile; - Printf(SourceFile, "players/%s.json", GetName().c_str()); - - bool res = LoadFromFile(SourceFile); + // Load from the UUID file: + bool res = LoadFromFile(GetUUIDFileName(m_UUID)); if (res) { return true; } + // Load from the offline UUID file, if allowed: + AString OfflineUUID = cClientHandle::GenerateOfflineUUID(GetName()); + if (cRoot::Get()->GetServer()->ShouldLoadOfflinePlayerData()) + { + res = LoadFromFile(GetUUIDFileName(OfflineUUID)); + if (res) + { + return true; + } + } + + // Load from the old-style name-based file, if allowed: + if (cRoot::Get()->GetServer()->ShouldLoadNamedPlayerData()) + { + AString OldStyleFileName = Printf("players/%s.json", GetName().c_str()); + res = LoadFromFile(OldStyleFileName); + if (res) + { + // Save in new format and remove the old file + SaveToDisk(); + cFile::Delete(OldStyleFileName); + return true; + } + } + + // None of the files loaded successfully + LOGD("Player data file not found for %s (%s, offline %s), will be reset to defaults.", + GetName().c_str(), m_UUID.c_str(), OfflineUUID.c_str() + ); return false; } @@ -1791,6 +1819,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName) bool cPlayer::SaveToDisk() { cFile::CreateFolder(FILE_IO_PREFIX + AString("players")); + cFile::CreateFolder(FILE_IO_PREFIX + AString("players/") + m_UUID.substr(0, 2)); // create the JSON data Json::Value JSON_PlayerPosition; @@ -1822,33 +1851,45 @@ bool cPlayer::SaveToDisk() root["foodSaturation"] = m_FoodSaturationLevel; root["foodTickTimer"] = m_FoodTickTimer; root["foodExhaustion"] = m_FoodExhaustionLevel; - root["world"] = GetWorld()->GetName(); root["isflying"] = IsFlying(); - - if (m_GameMode == GetWorld()->GetGameMode()) + root["lastknownname"] = GetName(); + if (m_World != NULL) { - root["gamemode"] = (int) eGameMode_NotSet; + root["world"] = m_World->GetName(); + if (m_GameMode == m_World->GetGameMode()) + { + root["gamemode"] = (int) eGameMode_NotSet; + } + else + { + root["gamemode"] = (int) m_GameMode; + } } else { - root["gamemode"] = (int) m_GameMode; + // This happens if the player is saved to new format after loading from the old format + root["world"] = m_LoadedWorldName; + root["gamemode"] = (int) eGameMode_NotSet; } Json::StyledWriter writer; std::string JsonData = writer.write(root); - AString SourceFile; - Printf(SourceFile, "players/%s.json", GetName().c_str() ); + AString SourceFile = GetUUIDFileName(m_UUID); cFile f; if (!f.Open(SourceFile, cFile::fmWrite)) { - LOGERROR("ERROR WRITING PLAYER \"%s\" TO FILE \"%s\" - cannot open file", GetName().c_str(), SourceFile.c_str()); + LOGWARNING("Error writing player \"%s\" to file \"%s\" - cannot open file. Player will lose their progress.", + GetName().c_str(), SourceFile.c_str() + ); return false; } if (f.Write(JsonData.c_str(), JsonData.size()) != (int)JsonData.size()) { - LOGERROR("ERROR WRITING PLAYER JSON TO FILE \"%s\"", SourceFile.c_str()); + LOGWARNING("Error writing player \"%s\" to file \"%s\" - cannot save data. Player will lose their progress. ", + GetName().c_str(), SourceFile.c_str() + ); return false; } @@ -1857,7 +1898,7 @@ bool cPlayer::SaveToDisk() cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats); if (!StatSerializer.Save()) { - LOGERROR("Could not save stats for player %s", GetName().c_str()); + LOGWARNING("Could not save stats for player %s", GetName().c_str()); return false; } @@ -2170,3 +2211,19 @@ void cPlayer::Detach() + +AString cPlayer::GetUUIDFileName(const AString & a_UUID) +{ + ASSERT(a_UUID.size() == 36); + + AString res("players/"); + res.append(a_UUID, 0, 2); + res.push_back('/'); + res.append(a_UUID, 2, AString::npos); + res.append(".json"); + return res; +} + + + + diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 7641b0c31..8f9b46e0f 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -528,6 +528,24 @@ protected: cStatManager m_Stats; + /** Flag representing whether the player is currently in a bed + Set by a right click on unoccupied bed, unset by a time fast forward or teleport */ + bool m_bIsInBed; + + /** How long till the player's inventory will be saved + Default save interval is #defined in PLAYER_INVENTORY_SAVE_INTERVAL */ + unsigned int m_TicksUntilNextSave; + + /** Flag used by food handling system to determine whether a teleport has just happened + Will not apply food penalties if found to be true; will set to false after processing + */ + bool m_bIsTeleporting; + + /** The UUID of the player, as read from the ClientHandle. + If no ClientHandle is given, the UUID is initialized to empty. */ + AString m_UUID; + + /** Sets the speed and sends it to the client, so that they are forced to move so. */ virtual void DoSetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ) override; @@ -554,19 +572,9 @@ protected: /** Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block) */ void ApplyFoodExhaustionFromMovement(); - /** Flag representing whether the player is currently in a bed - Set by a right click on unoccupied bed, unset by a time fast forward or teleport */ - bool m_bIsInBed; - - /** How long till the player's inventory will be saved - Default save interval is #defined in PLAYER_INVENTORY_SAVE_INTERVAL */ - unsigned int m_TicksUntilNextSave; - - /** Flag used by food handling system to determine whether a teleport has just happened - Will not apply food penalties if found to be true; will set to false after processing - */ - bool m_bIsTeleporting; - + /** Returns the filename for the player data based on the UUID given. + This can be used both for online and offline UUIDs. */ + AString GetUUIDFileName(const AString & a_UUID); } ; // tolua_export -- cgit v1.2.3 From f73042fb02ead13aa870f061a08f56d84ed1dc99 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 11 Jul 2014 23:12:57 +0200 Subject: Simplified the player data loading. --- src/Entities/Player.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 4e1314209..944ed643e 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1692,8 +1692,7 @@ bool cPlayer::LoadFromDisk(void) LoadPermissionsFromDisk(); // Load from the UUID file: - bool res = LoadFromFile(GetUUIDFileName(m_UUID)); - if (res) + if (LoadFromFile(GetUUIDFileName(m_UUID))) { return true; } @@ -1702,8 +1701,7 @@ bool cPlayer::LoadFromDisk(void) AString OfflineUUID = cClientHandle::GenerateOfflineUUID(GetName()); if (cRoot::Get()->GetServer()->ShouldLoadOfflinePlayerData()) { - res = LoadFromFile(GetUUIDFileName(OfflineUUID)); - if (res) + if (LoadFromFile(GetUUIDFileName(OfflineUUID))) { return true; } @@ -1713,18 +1711,19 @@ bool cPlayer::LoadFromDisk(void) if (cRoot::Get()->GetServer()->ShouldLoadNamedPlayerData()) { AString OldStyleFileName = Printf("players/%s.json", GetName().c_str()); - res = LoadFromFile(OldStyleFileName); - if (res) + if (LoadFromFile(OldStyleFileName)) { // Save in new format and remove the old file - SaveToDisk(); - cFile::Delete(OldStyleFileName); + if (SaveToDisk()) + { + cFile::Delete(OldStyleFileName); + } return true; } } // None of the files loaded successfully - LOGD("Player data file not found for %s (%s, offline %s), will be reset to defaults.", + LOG("Player data file not found for %s (%s, offline %s), will be reset to defaults.", GetName().c_str(), m_UUID.c_str(), OfflineUUID.c_str() ); return false; -- cgit v1.2.3