1
0
cuberite-2a/source/cEntity.cpp
faketruth 50a7722242 Terrain generation is synchronous again, async generation has bugs.
Made some funky smart pointer things for chunks.
Fixed a bug where the client would override the player position on the server and back again, resulting in sending too many chunks to the client which it doesn't even need.
Fixed some compiler warnings in cPickup.cpp


git-svn-id: http://mc-server.googlecode.com/svn/trunk@164 0a769ca7-a7f5-676a-18bf-c427514a06d6
2012-01-19 18:12:39 +00:00

305 lines
7.1 KiB
C++

#include "cEntity.h"
#include "cWorld.h"
#include "cChunk.h"
#include "cMCLogger.h"
#include "cServer.h"
#include "cRoot.h"
#include "Vector3d.h"
#include "Vector3f.h"
#include "Matrix4f.h"
#include "cReferenceManager.h"
#include "cClientHandle.h"
#include "packets/cPacket_DestroyEntity.h"
int cEntity::m_EntityCount = 0;
cEntity::cEntity(const double & a_X, const double & a_Y, const double & a_Z)
: m_UniqueID( 0 )
, m_Referencers( new cReferenceManager( cReferenceManager::RFMNGR_REFERENCERS ) )
, m_References( new cReferenceManager( cReferenceManager::RFMNGR_REFERENCES ) )
, m_ChunkX( 0 )
, m_ChunkY( 0 )
, m_ChunkZ( 0 )
, m_Pos( new Vector3d( a_X, a_Y, a_Z ) )
, m_bDirtyPosition( true )
, m_Rot( new Vector3f() )
, m_bDirtyOrientation( true )
, m_bDestroyed( false )
, m_EntityType( E_ENTITY )
, m_World( 0 )
, m_bRemovedFromChunk( false )
{
m_EntityCount++;
m_UniqueID = m_EntityCount;
}
cEntity::~cEntity()
{
if( !m_bDestroyed || !m_bRemovedFromChunk )
{
LOGERROR("ERROR: Entity deallocated without being destroyed %i or unlinked %i", m_bDestroyed, m_bRemovedFromChunk );
}
delete m_Referencers;
delete m_References;
delete m_Pos;
delete m_Rot;
}
void cEntity::Initialize( cWorld* a_World )
{
m_World = a_World;
m_World->AddEntity( this );
MoveToCorrectChunk(true);
}
void cEntity::WrapRotation()
{
while(m_Rot->x > 180.f) m_Rot->x-=360.f; // Wrap it
while(m_Rot->x < -180.f) m_Rot->x+=360.f;
while(m_Rot->y > 180.f) m_Rot->y-=360.f;
while(m_Rot->y < -180.f) m_Rot->y+=360.f;
}
void cEntity::MoveToCorrectChunk(bool a_bIgnoreOldChunk)
{
if( !m_World ) return; // Entity needs a world to move to a chunk
int ChunkX = 0, ChunkY = 0, ChunkZ = 0;
cWorld::BlockToChunk( (int)m_Pos->x, (int)m_Pos->y, (int)m_Pos->z, ChunkX, ChunkY, ChunkZ );
if(a_bIgnoreOldChunk || m_ChunkX != ChunkX || m_ChunkY != ChunkY || m_ChunkZ != ChunkZ)
{
LOG("From %i %i To %i %i", m_ChunkX, m_ChunkZ, ChunkX, ChunkZ );
cChunk* Chunk = 0;
if(!a_bIgnoreOldChunk)
Chunk = m_World->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
typedef std::list< cClientHandle* > ClientList;
ClientList BeforeClients;
if( Chunk )
{
Chunk->RemoveEntity( *this );
BeforeClients = Chunk->GetClients();
}
m_ChunkX = ChunkX; m_ChunkY = ChunkY; m_ChunkZ = ChunkZ;
cChunk* NewChunk = m_World->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
ClientList AfterClients;
if( NewChunk )
{
NewChunk->AddEntity( *this );
AfterClients = NewChunk->GetClients();
}
/********************
* I reaalllyyyy don't like this piece of code, but it's needed I guess (maybe there's a way to optimize this)
**/
// Now compare clients before with after
for( ClientList::iterator itr = BeforeClients.begin(); itr != BeforeClients.end(); ++itr )
{
bool bFound = false;
for( ClientList::iterator itr2 = AfterClients.begin(); itr2 != AfterClients.end(); ++itr2 )
{
if( *itr2 == *itr )
{
bFound = true;
break;
}
}
if( !bFound ) // Client was in old chunk, but not new, so destroy on that client
{
cPacket_DestroyEntity DestroyEntity( this );
(*itr)->Send( DestroyEntity );
}
}
// Now compare clients after with before
for( ClientList::iterator itr = AfterClients.begin(); itr != AfterClients.end(); ++itr )
{
bool bFound = false;
for( ClientList::iterator itr2 = BeforeClients.begin(); itr2 != BeforeClients.end(); ++itr2 )
{
if( *itr2 == *itr )
{
bFound = true;
break;
}
}
if( !bFound ) // Client is in the new chunk, but not in old, so spawn on the client
{
SpawnOn( *itr );
}
}
}
}
void cEntity::Destroy()
{
if( !m_bDestroyed )
{
m_bDestroyed = true;
if( !m_bRemovedFromChunk )
RemoveFromChunk(0);
}
}
void cEntity::RemoveFromChunk( cChunk* a_Chunk )
{
if( m_World )
{
cChunk* Chunk = ( a_Chunk ? a_Chunk : (cChunk*)m_World->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ ) );
if( Chunk )
{
cPacket_DestroyEntity DestroyEntity( this );
Chunk->Broadcast( DestroyEntity );
Chunk->RemoveEntity( *this );
m_bRemovedFromChunk = true;
}
}
}
CLASS_DEF_GETCLASS( cEntity );
bool cEntity::IsA( const char* a_EntityType )
{
//LOG("IsA( cEntity ) : %s", a_EntityType);
if( strcmp( a_EntityType, "cEntity" ) == 0 ) return true;
return false;
}
//////////////////////////////////////////////////////////////////////////
// Set orientations
void cEntity::SetRot( const Vector3f & a_Rot )
{
*m_Rot = a_Rot;
m_bDirtyOrientation = true;
}
void cEntity::SetRotation( float a_Rotation )
{
m_Rot->x = a_Rotation;
m_bDirtyOrientation = true;
}
void cEntity::SetPitch( float a_Pitch )
{
m_Rot->y = a_Pitch;
m_bDirtyOrientation = true;
}
void cEntity::SetRoll( float a_Roll )
{
m_Rot->z = a_Roll;
m_bDirtyOrientation = true;
}
//////////////////////////////////////////////////////////////////////////
// Get orientations
const Vector3f & cEntity::GetRot()
{
return *m_Rot;
}
float cEntity::GetRotation()
{
return m_Rot->x;
}
float cEntity::GetPitch()
{
return m_Rot->y;
}
float cEntity::GetRoll()
{
return m_Rot->z;
}
//////////////////////////////////////////////////////////////////////////
// Get look vector (this is NOT a rotation!)
Vector3f cEntity::GetLookVector()
{
Matrix4f m;
m.Init( Vector3f(), 0, m_Rot->x, -m_Rot->y );
Vector3f Look = m.Transform( Vector3f(0, 0, 1) );
LOG("Look: %0.1f %0.1f %0.1f", Look.x, Look.y, Look.z );
return Look;
}
//////////////////////////////////////////////////////////////////////////
// Set position
void cEntity::SetPosition( const Vector3d & a_Pos )
{
*m_Pos = a_Pos;
MoveToCorrectChunk();
m_bDirtyPosition = true;
}
void cEntity::SetPosition( const double & a_PosX, const double & a_PosY, const double & a_PosZ )
{
m_Pos->Set( a_PosX, a_PosY, a_PosZ );
MoveToCorrectChunk();
m_bDirtyPosition = true;
}
void cEntity::SetPosX( const double & a_PosX )
{
m_Pos->x = a_PosX;
MoveToCorrectChunk();
m_bDirtyPosition = true;
}
void cEntity::SetPosY( const double & a_PosY )
{
m_Pos->y = a_PosY;
MoveToCorrectChunk();
m_bDirtyPosition = true;
}
void cEntity::SetPosZ( const double & a_PosZ )
{
m_Pos->z = a_PosZ;
MoveToCorrectChunk();
m_bDirtyPosition = true;
}
//////////////////////////////////////////////////////////////////////////
// Get position
const Vector3d & cEntity::GetPosition()
{
return *m_Pos;
}
const double & cEntity::GetPosX()
{
return m_Pos->x;
}
const double & cEntity::GetPosY()
{
return m_Pos->y;
}
const double & cEntity::GetPosZ()
{
return m_Pos->z;
}
//////////////////////////////////////////////////////////////////////////
// Reference stuffs
void cEntity::AddReference( cEntity*& a_EntityPtr )
{
m_References->AddReference( a_EntityPtr );
a_EntityPtr->ReferencedBy( a_EntityPtr );
}
void cEntity::ReferencedBy( cEntity*& a_EntityPtr )
{
m_Referencers->AddReference( a_EntityPtr );
}
void cEntity::Dereference( cEntity*& a_EntityPtr )
{
m_Referencers->Dereference( a_EntityPtr );
}