diff --git a/source/BlockTracer.h b/source/BlockTracer.h index 6d67f1052..d0a34811d 100644 --- a/source/BlockTracer.h +++ b/source/BlockTracer.h @@ -31,12 +31,12 @@ public: /** Called on each block encountered along the path, including the first block (path start) When this callback returns true, the tracing is aborted. */ - virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; + virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) = 0; /** Called on each block encountered along the path, including the first block (path start), if chunk data is not loaded When this callback returns true, the tracing is aborted. */ - virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ) { return false; } + virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) { return false; } /** Called when the path goes out of world, either below (a_BlockY < 0) or above (a_BlockY >= cChunkDef::Height) The coords specify the exact point at which the path exited the world. diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index 350cad95b..4983943a9 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -7,6 +7,57 @@ #include "ProjectileEntity.h" #include "../ClientHandle.h" #include "Player.h" +#include "../LineBlockTracer.h" + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cProjectileTracerCallback: + +class cProjectileTracerCallback : + public cBlockTracer::cCallbacks +{ +public: + cProjectileTracerCallback(cProjectileEntity * a_Projectile) : + m_Projectile(a_Projectile) + { + } + +protected: + cProjectileEntity * m_Projectile; + + virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override + { + if (g_BlockIsSolid[a_BlockType]) + { + // The projectile hit a solid block + m_Projectile->OnHitSolidBlock(a_BlockX, a_BlockY, a_BlockZ, a_EntryFace); + return true; + } + + // Convey some special effects from special blocks: + switch (a_BlockType) + { + case E_BLOCK_LAVA: + case E_BLOCK_STATIONARY_LAVA: + { + m_Projectile->StartBurning(30); + break; + } + case E_BLOCK_WATER: + case E_BLOCK_STATIONARY_WATER: + { + m_Projectile->StopBurning(); + break; + } + } // switch (a_BlockType) + + // Continue tracing + return false; + } +} ; @@ -18,7 +69,8 @@ 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_Creator(a_Creator), + m_IsInGround(false) { } @@ -29,7 +81,8 @@ 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_Creator(a_Creator), + m_IsInGround(false) { SetSpeed(a_Speed); } @@ -60,6 +113,35 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, +void cProjectileEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +{ + // TODO: Set proper position based on what face was hit + switch (a_BlockFace) + { + case BLOCK_FACE_TOP: SetPosition(0.5 + a_BlockX, 1.0 + a_BlockY, 0.5 + a_BlockZ); break; + case BLOCK_FACE_BOTTOM: SetPosition(0.5 + a_BlockX, a_BlockY, 0.5 + a_BlockZ); break; + case BLOCK_FACE_EAST: SetPosition( a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break; + case BLOCK_FACE_WEST: SetPosition(1.0 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break; + case BLOCK_FACE_NORTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 1.0 + a_BlockZ); break; + case BLOCK_FACE_SOUTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, a_BlockZ); break; + case BLOCK_FACE_NONE: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break; + } + SetSpeed(0, 0, 0); + + // DEBUG: + LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, hit solid block at face %d", + m_UniqueID, + GetPosX(), GetPosY(), GetPosZ(), + a_BlockFace + ); + + m_IsInGround = true; +} + + + + + AString cProjectileEntity::GetMCAClassName(void) const { switch (m_ProjectileKind) @@ -83,6 +165,51 @@ AString cProjectileEntity::GetMCAClassName(void) const +void cProjectileEntity::Tick(float a_Dt, cChunk & a_Chunk) +{ + super::Tick(a_Dt, a_Chunk); + BroadcastMovementUpdate(); +} + + + + + +void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) +{ + if (m_IsInGround) + { + // Already-grounded projectiles don't move at all + 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)) + { + // Nothing in the way, update the position + SetPosition(NextPos); + } + + // Add gravity effect to the vertical speed component: + SetSpeedY(GetSpeedY() + m_Gravity / 20); + + // DEBUG: + LOGD("Arrow %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}", + m_UniqueID, + GetPosX(), GetPosY(), GetPosZ(), + GetSpeedX(), GetSpeedY(), GetSpeedZ() + ); +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cArrowEntity: @@ -118,22 +245,6 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const -void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk) -{ - super::Tick(a_Dt, a_Chunk); - - // DEBUG: - LOGD("Arrow %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}", - m_UniqueID, - GetPosX(), GetPosY(), GetPosZ(), - GetSpeedX(), GetSpeedY(), GetSpeedZ() - ); -} - - - - - void cArrowEntity::SpawnOn(cClientHandle & a_Client) { a_Client.SendSpawnObject(*this, pkArrow, 0, 0, 0); diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h index 345730d19..7a97a2215 100644 --- a/source/Entities/ProjectileEntity.h +++ b/source/Entities/ProjectileEntity.h @@ -47,8 +47,8 @@ public: static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed = NULL); - /// Called by the physics blocktracer when the entity hits a solid block, the coords and the face hit is given - virtual void OnHitSolidBlock(double a_BlockX, double a_BlockY, double a_BlockZ, char a_BlockFace) {}; + /// Called by the physics blocktracer when the entity hits a solid block, the block's coords and the face hit is given + virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace); // tolua_begin @@ -72,6 +72,10 @@ protected: /// True if the projectile has hit the ground and is stuck there bool m_IsInGround; + + // cEntity overrides: + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; + virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; } ; @@ -127,7 +131,6 @@ protected: double m_DamageCoeff; // cEntity overrides: - virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void SpawnOn(cClientHandle & a_Client) override; // tolua_begin diff --git a/source/LineBlockTracer.cpp b/source/LineBlockTracer.cpp index 03464314a..7cc14089d 100644 --- a/source/LineBlockTracer.cpp +++ b/source/LineBlockTracer.cpp @@ -55,6 +55,7 @@ bool cLineBlockTracer::Trace(double a_StartX, double a_StartY, double a_StartZ, m_DirX = (m_StartX < m_EndX) ? 1 : -1; m_DirY = (m_StartY < m_EndY) ? 1 : -1; m_DirZ = (m_StartZ < m_EndZ) ? 1 : -1; + m_CurrentFace = BLOCK_FACE_NONE; // Check the start coords, adjust into the world: if (m_StartY < 0) @@ -178,9 +179,9 @@ bool cLineBlockTracer::MoveToNextBlock(void) // Based on the wall hit, adjust the current coords switch (Direction) { - case dirX: m_CurrentX += m_DirX; break; - case dirY: m_CurrentY += m_DirY; break; - case dirZ: m_CurrentZ += m_DirZ; break; + case dirX: m_CurrentX += m_DirX; m_CurrentFace = (m_DirX > 0) ? BLOCK_FACE_EAST : BLOCK_FACE_WEST; break; + case dirY: m_CurrentY += m_DirY; m_CurrentFace = (m_DirY > 0) ? BLOCK_FACE_BOTTOM : BLOCK_FACE_TOP; break; + case dirZ: m_CurrentZ += m_DirZ; m_CurrentFace = (m_DirZ > 0) ? BLOCK_FACE_SOUTH : BLOCK_FACE_NORTH; break; case dirNONE: return false; } return true; @@ -211,7 +212,7 @@ bool cLineBlockTracer::Item(cChunk * a_Chunk) int RelX = m_CurrentX - a_Chunk->GetPosX() * cChunkDef::Width; int RelZ = m_CurrentZ - a_Chunk->GetPosZ() * cChunkDef::Width; a_Chunk->GetBlockTypeMeta(RelX, m_CurrentY, RelZ, BlockType, BlockMeta); - if (m_Callbacks->OnNextBlock(m_CurrentX, m_CurrentY, m_CurrentZ, BlockType, BlockMeta)) + if (m_Callbacks->OnNextBlock(m_CurrentX, m_CurrentY, m_CurrentZ, BlockType, BlockMeta, m_CurrentFace)) { // The callback terminated the trace return false; @@ -219,7 +220,7 @@ bool cLineBlockTracer::Item(cChunk * a_Chunk) } else { - if (m_Callbacks->OnNextBlockNoData(m_CurrentX, m_CurrentY, m_CurrentZ)) + if (m_Callbacks->OnNextBlockNoData(m_CurrentX, m_CurrentY, m_CurrentZ, m_CurrentFace)) { // The callback terminated the trace return false; diff --git a/source/LineBlockTracer.h b/source/LineBlockTracer.h index 4616cb191..ccbb70ea6 100644 --- a/source/LineBlockTracer.h +++ b/source/LineBlockTracer.h @@ -60,6 +60,9 @@ protected: // The current block int m_CurrentX, m_CurrentY, m_CurrentZ; + + // The face through which the current block has been entered + char m_CurrentFace; /// Adjusts the start point above the world to just at the world's top diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index 27c6684f2..87efecd35 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -1649,7 +1649,7 @@ public: { } - virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override + virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override { if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlock")) { @@ -1661,6 +1661,7 @@ public: m_LuaState.Push(a_BlockZ); m_LuaState.Push(a_BlockType); m_LuaState.Push(a_BlockMeta); + m_LuaState.Push(a_EntryFace); if (!m_LuaState.CallFunction(1)) { return false; @@ -1674,7 +1675,7 @@ public: return res; } - virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) override { if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlockNoData")) { @@ -1684,6 +1685,7 @@ public: m_LuaState.Push(a_BlockX); m_LuaState.Push(a_BlockY); m_LuaState.Push(a_BlockZ); + m_LuaState.Push(a_EntryFace); if (!m_LuaState.CallFunction(1)) { return false; diff --git a/source/Vector3d.h b/source/Vector3d.h index 6f28a857b..ecc72e421 100644 --- a/source/Vector3d.h +++ b/source/Vector3d.h @@ -30,12 +30,13 @@ public: // tolua_export void operator -= ( Vector3d* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; } void operator *= ( double a_f ) { x *= a_f; y *= a_f; z *= a_f; } - Vector3d operator + ( const Vector3d& v2 ) const { return Vector3d( x + v2.x, y + v2.y, z + v2.z ); } // tolua_export - Vector3d operator + ( const Vector3d* v2 ) const { return Vector3d( x + v2->x, y + v2->y, z + v2->z ); } // tolua_export - Vector3d operator - ( const Vector3d& v2 ) const { return Vector3d( x - v2.x, y - v2.y, z - v2.z ); } // tolua_export - Vector3d operator - ( const Vector3d* v2 ) const { return Vector3d( x - v2->x, y - v2->y, z - v2->z ); } // tolua_export - Vector3d operator * ( const double f ) const { return Vector3d( x * f, y * f, z * f ); } // tolua_export - Vector3d operator * ( const Vector3d& v2 ) const { return Vector3d( x * v2.x, y * v2.y, z * v2.z ); } // tolua_export + Vector3d operator + (const Vector3d & v2) const { return Vector3d(x + v2.x, y + v2.y, z + v2.z ); } // tolua_export + Vector3d operator + (const Vector3d * v2) const { return Vector3d(x + v2->x, y + v2->y, z + v2->z ); } // tolua_export + Vector3d operator - (const Vector3d & v2) const { return Vector3d(x - v2.x, y - v2.y, z - v2.z ); } // tolua_export + Vector3d operator - (const Vector3d * v2) const { return Vector3d(x - v2->x, y - v2->y, z - v2->z ); } // tolua_export + Vector3d operator * (const double f) const { return Vector3d(x * f, y * f, z * f ); } // tolua_export + Vector3d operator * (const Vector3d & v2) const { return Vector3d(x * v2.x, y * v2.y, z * v2.z ); } // tolua_export + Vector3d operator / (const double f) const { return Vector3d(x / f, y / f, z / f ); } // tolua_export double x, y, z; // tolua_export