1
0

Removed some more cChunkPtr usage

git-svn-id: http://mc-server.googlecode.com/svn/trunk@298 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
madmaxoft@gmail.com 2012-02-20 16:39:00 +00:00
parent 0b616909e3
commit d592882fe0
13 changed files with 372 additions and 114 deletions

View File

@ -1148,7 +1148,7 @@ bool cChunk::HasAnyClients(void)
void cChunk::AddEntity( cEntity * a_Entity )
void cChunk::AddEntity( cEntity * a_Entity)
{
cCSLock Lock(m_CSEntities);
if (a_Entity->GetEntityType() != cEntity::E_PLAYER)
@ -1171,9 +1171,13 @@ void cChunk::RemoveEntity(cEntity * a_Entity)
m_Entities.remove(a_Entity);
SizeAfter = m_Entities.size();
}
if ((a_Entity->GetEntityType() != cEntity::E_PLAYER) && (SizeBefore != SizeAfter))
if (SizeBefore != SizeAfter)
{
MarkDirty();
// Mark as dirty if it was a server-generated entity:
if (a_Entity->GetEntityType() != cEntity::E_PLAYER)
{
MarkDirty();
}
}
}

View File

@ -70,6 +70,23 @@ public:
/** Interface class used for comparing clients of two chunks.
Used primarily for entity moving while both chunks are locked.
*/
class cClientDiffCallback
{
public:
/// Called for clients that are in Chunk1 and not in Chunk2,
virtual void Removed(cClientHandle * a_Client) = 0;
/// Called for clients that are in Chunk2 and not in Chunk1.
virtual void Added(cClientHandle * a_Client) = 0;
} ;
struct sSetBlock
{
int x, y, z;
@ -121,7 +138,7 @@ public:
/// Returns true if there is a block entity at the coords specified
bool HasBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ);
void Tick(float a_Dt, MTRand & a_TickRandom);
int GetPosX() { return m_PosX; }
@ -149,7 +166,7 @@ public:
bool HasClient (cClientHandle* a_Client );
bool HasAnyClients(void); // Returns true if theres any client in the chunk; false otherwise
void AddEntity( cEntity * a_Entity );
void AddEntity( cEntity * a_Entity);
void RemoveEntity( cEntity * a_Entity);
void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // [x, y, z] in world block coords
@ -206,6 +223,8 @@ public:
private:
friend class cChunkMap;
bool m_IsValid; // True if the chunk is loaded / generated
bool m_IsDirty; // True if the chunk has changed since it was last saved
bool m_IsSaving; // True if the chunk is being saved
@ -251,6 +270,9 @@ private:
void SpreadLightOfBlockZ(char* a_LightBuffer, int a_X, int a_Y, int a_Z);
void CreateBlockEntities(void);
// Makes a copy of the list
cClientHandleList GetAllClients(void) const {return m_LoadedByClient; }
};
typedef std::tr1::shared_ptr<cChunk> cChunkPtr;

View File

@ -6,7 +6,8 @@
// The object takes requests for generating chunks and processes them in a separate thread one by one.
// The requests are not added to the queue if there is already a request with the same coords
// Before generating, the thread checks if the chunk hasn't been already generated.
// It is theoretically possible to have multiple generator threads by having multiple instances of this object (if the cChunkPtr is thread-safe)
// It is theoretically possible to have multiple generator threads by having multiple instances of this object
// but then it MAY happen that the chunk is generated twice
// If the generator queue is overloaded, the generator skips chunks with no clients in them

View File

@ -6,6 +6,7 @@
#include "cWorld.h"
#include "cRoot.h"
#include "cMakeDir.h"
#include "cPlayer.h"
#ifndef _WIN32
#include <cstdlib> // abs
@ -15,9 +16,6 @@
#include <json/json.h>
#define USE_MEMCPY
@ -136,6 +134,24 @@ cChunkPtr cChunkMap::GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ )
void cChunkMap::BroadcastToChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cPacket & a_Packet, cClientHandle * a_Exclude)
{
// Broadcasts a_Packet to all clients in the chunk where block [x, y, z] is, except to client a_Exclude
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
if (Chunk == NULL)
{
return;
}
// It's perfectly legal to broadcast packets even to invalid chunks!
Chunk->Broadcast(a_Packet, a_Exclude);
}
void cChunkMap::BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_Packet, cClientHandle * a_Exclude)
{
// Broadcasts a_Packet to all clients in the chunk where block [x, y, z] is, except to client a_Exclude
@ -143,13 +159,13 @@ void cChunkMap::BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_P
cCSLock Lock(m_CSLayers);
int ChunkX, ChunkZ;
BlockToChunk(a_X, a_Y, a_Z, ChunkX, ChunkZ);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if (Chunk == NULL)
{
return;
}
// Packets can be broadcasted even to invalid chunks!
Chunk->Broadcast(a_Packet);
// It's perfectly legal to broadcast packets even to invalid chunks!
Chunk->Broadcast(a_Packet, a_Exclude);
}
@ -402,6 +418,122 @@ void cChunkMap::FastSetBlocks(sSetBlockList & a_BlockList)
void cChunkMap::CollectPickupsByPlayer(cPlayer * a_Player)
{
int BlockX = (int)(a_Player->GetPosX()); // Truncating doesn't matter much; we're scanning entire chunks anyway
int BlockY = (int)(a_Player->GetPosY());
int BlockZ = (int)(a_Player->GetPosZ());
int ChunkX, ChunkZ, ChunkY = ZERO_CHUNK_Y;
AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
int OtherChunkX = ChunkX + ((BlockX > 8) ? 1 : -1);
int OtherChunkZ = ChunkZ + ((BlockZ > 8) ? 1 : -1);
cCSLock Lock(m_CSLayers);
GetChunkNoGen(ChunkX, ChunkY, ChunkZ)->CollectPickupsByPlayer(a_Player);
// Check the neighboring chunks as well:
GetChunkNoGen(OtherChunkX, ChunkY, ChunkZ )->CollectPickupsByPlayer(a_Player);
GetChunkNoGen(OtherChunkX, ChunkY, OtherChunkZ)->CollectPickupsByPlayer(a_Player);
GetChunkNoGen(ChunkX, ChunkY, ChunkZ )->CollectPickupsByPlayer(a_Player);
GetChunkNoGen(ChunkX, ChunkY, OtherChunkZ)->CollectPickupsByPlayer(a_Player);
}
void cChunkMap::CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkY2, int a_ChunkZ2, cClientDiffCallback & a_Callback)
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk1 = GetChunkNoGen(a_ChunkX1, a_ChunkY1, a_ChunkZ1);
if (Chunk1 == NULL)
{
return;
}
cChunkPtr Chunk2 = GetChunkNoGen(a_ChunkX2, a_ChunkY2, a_ChunkZ2);
if (Chunk2 == NULL)
{
return;
}
cClientHandleList Clients1(Chunk1->GetAllClients());
cClientHandleList Clients2(Chunk2->GetAllClients());
// Find "removed" clients:
for (cClientHandleList::iterator itr1 = Clients1.begin(); itr1 != Clients1.end(); ++itr1)
{
bool Found = false;
for (cClientHandleList::iterator itr2 = Clients2.begin(); itr2 != Clients2.end(); ++itr2)
{
if (*itr1 == *itr2)
{
Found = true;
break;
}
} // for itr2 - Clients2[]
if (!Found)
{
a_Callback.Removed(*itr1);
}
} // for itr1 - Clients1[]
// Find "added" clients:
for (cClientHandleList::iterator itr2 = Clients2.begin(); itr2 != Clients2.end(); ++itr2)
{
bool Found = false;
for (cClientHandleList::iterator itr1 = Clients1.begin(); itr1 != Clients1.end(); ++itr1)
{
if (*itr1 == *itr2)
{
Found = true;
break;
}
} // for itr1 - Clients1[]
if (!Found)
{
a_Callback.Added(*itr2);
}
} // for itr2 - Clients2[]
}
void cChunkMap::MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ)
{
cCSLock Lock(m_CSLayers);
cChunkPtr OldChunk = GetChunkNoGen(a_Entity->GetChunkX(), a_Entity->GetChunkY(), a_Entity->GetChunkZ());
if (OldChunk != NULL)
{
OldChunk->RemoveEntity(a_Entity);
}
cChunkPtr NewChunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
if (NewChunk != NULL)
{
NewChunk->AddEntity(a_Entity);
}
}
void cChunkMap::RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ)
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
{
return;
}
Chunk->RemoveEntity(a_Entity);
}
void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom )
{
cCSLock Lock(m_CSLayers);

View File

@ -32,9 +32,14 @@ public:
cChunkPtr GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ ); // Also queues the chunk for loading if not valid; doesn't generate
// Direct action methods:
/// Broadcast a_Packet to all clients in the chunk specified
void BroadcastToChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cPacket & a_Packet, cClientHandle * a_Exclude = NULL);
/// Broadcasts a_Packet to all clients in the chunk where block [x, y, z] is, except to client a_Exclude
void BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_Packet, cClientHandle * a_Exclude = NULL);
void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // a_Player rclked block entity at the coords specified, handle it
/// a_Player rclked block entity at the coords specified, handle it
void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z);
void MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
void MarkChunkSaving (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
@ -48,6 +53,16 @@ public:
void SpreadChunkLighting(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
int GetHeight (int a_BlockX, int a_BlockZ);
void FastSetBlocks (sSetBlockList & a_BlockList);
void CollectPickupsByPlayer(cPlayer * a_Player);
/// Compares clients of two chunks, calls the callback accordingly
void CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkY2, int a_ChunkZ2, cClientDiffCallback & a_Callback);
/// Moves the entity from its current chunk to the new chunk specified
void MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ);
/// Removes the entity from the chunk specified
void RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ);
void Tick( float a_Dt, MTRand & a_TickRand );

View File

@ -66,6 +66,7 @@
#include "packets/cPacket_Ping.h"
#include "packets/cPacket_PlayerListItem.h"
#include "packets/cPacket_NamedEntitySpawn.h"
#include "packets/cPacket_MapChunk.h"
@ -1784,7 +1785,9 @@ void cClientHandle::CheckIfWorldDownloaded(void)
void cClientHandle::SendConfirmPosition(void)
{
LOG("Spawning player \"%s\"", m_Username.c_str());
LOG("Spawning player \"%s\" at {%.2f, %.2f, %.2f}",
m_Username.c_str(), m_Player->GetPosX(), m_Player->GetPosY(), m_Player->GetPosZ()
);
m_State = csConfirmingPos;

View File

@ -106,27 +106,60 @@ void cEntity::MoveToCorrectChunk(bool a_bIgnoreOldChunk)
return;
}
if (!a_bIgnoreOldChunk)
class cMover :
public cClientDiffCallback
{
cChunkPtr OldChunk = m_World->GetChunk(m_ChunkX, m_ChunkY, m_ChunkZ);
OldChunk->RemoveEntity(this);
cPacket_DestroyEntity DestroyEntity( this );
OldChunk->Broadcast(DestroyEntity);
}
virtual void Removed(cClientHandle * a_Client) override
{
if (m_IgnoreOldChunk)
{
return;
}
if (m_Destroy == NULL)
{
m_Destroy = new cPacket_DestroyEntity(m_Entity);
}
a_Client->Send(m_Destroy);
}
virtual void Added(cClientHandle * a_Client) override
{
if (m_Spawn == NULL)
{
m_Spawn = m_Entity->GetSpawnPacket(); // Only create the packet when needed
}
if (m_Spawn != NULL)
{
a_Client->Send(m_Spawn);
}
}
cPacket * m_Destroy;
cPacket * m_Spawn;
bool m_IgnoreOldChunk;
cEntity * m_Entity;
public:
cMover(cEntity * a_Entity, bool a_IgnoreOldChunk) :
m_Destroy(NULL),
m_Spawn(NULL),
m_IgnoreOldChunk(a_IgnoreOldChunk),
m_Entity(a_Entity)
{}
~cMover()
{
delete m_Spawn;
delete m_Destroy;
}
} Mover(this, a_bIgnoreOldChunk);
m_World->CompareChunkClients(m_ChunkX, m_ChunkY, m_ChunkZ, ChunkX, ChunkY, ChunkZ, Mover);
m_World->MoveEntityToChunk(this, ChunkX, ChunkY, ChunkZ);
m_ChunkX = ChunkX;
m_ChunkY = ChunkY;
m_ChunkZ = ChunkZ;
cChunkPtr NewChunk = m_World->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
if ( NewChunk != NULL )
{
NewChunk->AddEntity( this );
std::auto_ptr<cPacket> SpawnPacket(GetSpawnPacket());
if (SpawnPacket.get() != NULL)
{
NewChunk->Broadcast(SpawnPacket.get());
}
}
}
@ -151,19 +184,13 @@ void cEntity::Destroy()
void cEntity::RemoveFromChunk(void)
{
if ( m_World == NULL )
if (m_World == NULL)
{
return;
}
cChunkPtr Chunk = m_World->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
if ( Chunk != NULL )
{
cPacket_DestroyEntity DestroyEntity( this );
Chunk->Broadcast( DestroyEntity );
Chunk->RemoveEntity( this );
m_bRemovedFromChunk = true;
}
m_World->RemoveEntityFromChunk(this, m_ChunkX, m_ChunkY, m_ChunkZ);
m_bRemovedFromChunk = true;
}
@ -180,11 +207,7 @@ void cEntity::SpawnOn(cClientHandle * a_Client)
if (a_Client == NULL)
{
cChunkPtr Chunk = m_World->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
if ( Chunk != NULL )
{
Chunk->Broadcast(SpawnPacket.get());
}
m_World->BroadcastToChunk(m_ChunkX, m_ChunkY, m_ChunkZ, *SpawnPacket.get(), NULL);
}
else
{

View File

@ -79,6 +79,10 @@ public: //tolua_export
float GetPitch (void) const {return m_Rot.y; } //tolua_export
float GetRoll (void) const {return m_Rot.z; } //tolua_export
Vector3f GetLookVector(); //tolua_export
int GetChunkX(void) const {return m_ChunkX; }
int GetChunkY(void) const {return m_ChunkY; }
int GetChunkZ(void) const {return m_ChunkZ; }
void SetPosX( const double & a_PosX ); //tolua_export
void SetPosY( const double & a_PosY ); //tolua_export

View File

@ -206,31 +206,27 @@ void cMonster::Tick(float a_Dt)
void cMonster::ReplicateMovement()
{
cChunkPtr InChunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
if ( !InChunk->IsValid() )
{
return;
}
if(m_bDirtyOrientation && !m_bDirtyPosition)
{
cPacket_EntityLook EntityLook( this );
InChunk->Broadcast( EntityLook );
m_World->BroadcastToChunk(m_ChunkX, m_ChunkY, m_ChunkZ, EntityLook );
m_bDirtyOrientation = false;
}
if( m_bDirtyPosition )
{
float DiffX = (float)(GetPosX() - m_LastPosX );
float DiffY = (float)(GetPosY() - m_LastPosY );
float DiffZ = (float)(GetPosZ() - m_LastPosZ );
float SqrDist = DiffX*DiffX + DiffY*DiffY + DiffZ*DiffZ;
if( SqrDist > 4*4 // 4 blocks is max Relative Move
|| cWorld::GetTime() - m_TimeLastTeleportPacket > 2 ) // Send an absolute position every 2 seconds
if (
(SqrDist > 4 * 4) // 4 blocks is max Relative Move
|| (cWorld::GetTime() - m_TimeLastTeleportPacket > 2 ) // Send an absolute position every 2 seconds
)
{
//LOG("Teleported %f", sqrtf(SqrDist) );
cPacket_TeleportEntity TeleportEntity( this );
InChunk->Broadcast( TeleportEntity );
m_World->BroadcastToChunk(m_ChunkX, m_ChunkY, m_ChunkZ, TeleportEntity);
m_TimeLastTeleportPacket = cWorld::GetTime();
}
else
@ -239,21 +235,21 @@ void cMonster::ReplicateMovement()
{
cPacket_RelativeEntityMoveLook RelativeEntityMoveLook;
RelativeEntityMoveLook.m_UniqueID = GetUniqueID();
RelativeEntityMoveLook.m_MoveX = (char)(DiffX*32);
RelativeEntityMoveLook.m_MoveY = (char)(DiffY*32);
RelativeEntityMoveLook.m_MoveZ = (char)(DiffZ*32);
RelativeEntityMoveLook.m_Yaw = (char)((GetRotation()/360.f)*256);
RelativeEntityMoveLook.m_MoveX = (char)(DiffX*32);
RelativeEntityMoveLook.m_MoveY = (char)(DiffY*32);
RelativeEntityMoveLook.m_MoveZ = (char)(DiffZ*32);
RelativeEntityMoveLook.m_Yaw = (char)((GetRotation()/360.f)*256);
RelativeEntityMoveLook.m_Pitch = (char)((GetPitch()/360.f)*256);
InChunk->Broadcast( RelativeEntityMoveLook );
m_World->BroadcastToChunk(m_ChunkX, m_ChunkY, m_ChunkZ, RelativeEntityMoveLook );
}
else
{
cPacket_RelativeEntityMove RelativeEntityMove;
RelativeEntityMove.m_UniqueID = GetUniqueID();
RelativeEntityMove.m_MoveX = (char)(DiffX*32);
RelativeEntityMove.m_MoveY = (char)(DiffY*32);
RelativeEntityMove.m_MoveZ = (char)(DiffZ*32);
InChunk->Broadcast( RelativeEntityMove );
RelativeEntityMove.m_MoveX = (char)(DiffX*32);
RelativeEntityMove.m_MoveY = (char)(DiffY*32);
RelativeEntityMove.m_MoveZ = (char)(DiffZ*32);
m_World->BroadcastToChunk(m_ChunkX, m_ChunkY, m_ChunkZ, RelativeEntityMove );
}
}
m_LastPosX = GetPosX();

View File

@ -80,8 +80,7 @@ void cPawn::TakeDamage( int a_Damage, cEntity* a_Instigator )
cPacket_EntityStatus Status;
Status.m_UniqueID = GetUniqueID();
Status.m_Status = cPacket_EntityStatus::STATUS_TAKEDAMAGE;
cChunkPtr Chunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
Chunk->Broadcast( Status );
m_World->BroadcastToChunk(m_ChunkX, m_ChunkY, m_ChunkZ, Status);
if (m_Health <= 0)
{
@ -105,8 +104,7 @@ void cPawn::KilledBy( cEntity* a_Killer )
cPacket_EntityStatus Status;
Status.m_UniqueID = GetUniqueID();
Status.m_Status = cPacket_EntityStatus::STATUS_DIE;
cChunkPtr Chunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
Chunk->Broadcast( Status ); // Die
m_World->BroadcastToChunk(m_ChunkX, m_ChunkY, m_ChunkZ, Status);
}
@ -152,12 +150,10 @@ void cPawn::Tick(float a_Dt)
void cPawn::SetMetaData(MetaData a_MetaData)
{
cChunkPtr InChunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
//Broadcast new status to clients in the chunk
m_MetaData = a_MetaData;
cPacket_Metadata md(a_MetaData, GetUniqueID());
InChunk->Broadcast(md);
m_World->BroadcastToChunk(m_ChunkX, m_ChunkY, m_ChunkZ, md);
}

View File

@ -101,15 +101,27 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
m_Pos.x = cRoot::Get()->GetDefaultWorld()->GetSpawnX();
m_Pos.y = cRoot::Get()->GetDefaultWorld()->GetSpawnY();
m_Pos.z = cRoot::Get()->GetDefaultWorld()->GetSpawnZ();
LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}",
a_PlayerName.c_str(), m_Pos.x, m_Pos.y, m_Pos.z
);
}
}
void cPlayer::Initialize( cWorld* a_World )
{
cPawn::Initialize( a_World );
GetWorld()->AddPlayer( this );
}
cPlayer::~cPlayer(void)
{
SaveToDisk();
@ -135,6 +147,10 @@ cPlayer::~cPlayer(void)
cPacket * cPlayer::GetSpawnPacket(void) const
{
LOGD("cPlayer::GetSpawnPacket for \"%s\" at pos {%.2f, %.2f, %.2f}",
m_pState->PlayerName.c_str(), m_Pos.x, m_Pos.y, m_Pos.z
);
if (!m_bVisible )
{
return NULL;
@ -159,14 +175,12 @@ cPacket * cPlayer::GetSpawnPacket(void) const
void cPlayer::Tick(float a_Dt)
{
cChunkPtr InChunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
cPawn::Tick(a_Dt);
if (m_bDirtyOrientation && !m_bDirtyPosition)
{
cPacket_EntityLook EntityLook( this );
InChunk->Broadcast( EntityLook, m_ClientHandle );
m_World->BroadcastToChunk(m_ChunkX, m_ChunkY, m_ChunkZ, EntityLook, m_ClientHandle );
m_bDirtyOrientation = false;
}
else if (m_bDirtyPosition )
@ -184,7 +198,7 @@ void cPlayer::Tick(float a_Dt)
{
//LOG("Teleported %f", sqrtf(SqrDist) );
cPacket_TeleportEntity TeleportEntity( this );
InChunk->Broadcast( TeleportEntity, m_ClientHandle );
m_World->BroadcastToChunk(m_ChunkX, m_ChunkY, m_ChunkZ, TeleportEntity, m_ClientHandle);
m_TimeLastTeleportPacket = cWorld::GetTime();
}
else
@ -198,7 +212,7 @@ void cPlayer::Tick(float a_Dt)
RelativeEntityMoveLook.m_MoveZ = (char)(DiffZ*32);
RelativeEntityMoveLook.m_Yaw = (char)((GetRotation()/360.f)*256);
RelativeEntityMoveLook.m_Pitch = (char)((GetPitch()/360.f)*256);
InChunk->Broadcast( RelativeEntityMoveLook, m_ClientHandle );
m_World->BroadcastToChunk(m_ChunkX, m_ChunkY, m_ChunkZ, RelativeEntityMoveLook, m_ClientHandle );
}
else
{
@ -207,7 +221,7 @@ void cPlayer::Tick(float a_Dt)
RelativeEntityMove.m_MoveX = (char)(DiffX*32);
RelativeEntityMove.m_MoveY = (char)(DiffY*32);
RelativeEntityMove.m_MoveZ = (char)(DiffZ*32);
InChunk->Broadcast( RelativeEntityMove, m_ClientHandle );
m_World->BroadcastToChunk(m_ChunkX, m_ChunkY, m_ChunkZ, RelativeEntityMove, m_ClientHandle );
}
}
m_LastPosX = GetPosX();
@ -217,10 +231,9 @@ void cPlayer::Tick(float a_Dt)
m_ClientHandle->StreamChunks();
}
if( m_Health > 0 ) // make sure player is alive
if ( m_Health > 0 ) // make sure player is alive
{
// TODO: Don't only check in current chunks, but also close chunks (chunks within range)
GetWorld()->GetChunk(m_ChunkX, m_ChunkY, m_ChunkZ)->CollectPickupsByPlayer(this);
m_World->CollectPickupsByPlayer(this);
}
cTimer t1;
@ -521,6 +534,8 @@ void cPlayer::TeleportTo( const double & a_PosX, const double & a_PosY, const do
void cPlayer::MoveTo( const Vector3d & a_NewPos )
{
// TODO: should do some checks to see if player is not moving through terrain
// TODO: Official server refuses position packets too far away from each other, kicking "hacked" clients; we should, too
SetPosition( a_NewPos );
}
@ -539,11 +554,7 @@ void cPlayer::SetVisible( bool a_bVisible )
{
m_bVisible = false;
cPacket_DestroyEntity DestroyEntity( this );
cChunkPtr Chunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
if ( Chunk != NULL )
{
Chunk->Broadcast( DestroyEntity ); // Destroy on all clients
}
m_World->BroadcastToChunk(m_ChunkX, m_ChunkY, m_ChunkZ, DestroyEntity ); // Destroy on all clients
}
}
@ -560,6 +571,10 @@ void cPlayer::AddToGroup( const char* a_GroupName )
ResolvePermissions();
}
bool cPlayer::CanUseCommand( const char* a_Command )
{
for( GroupList::iterator itr = m_pState->Groups.begin(); itr != m_pState->Groups.end(); ++itr )
@ -753,12 +768,7 @@ bool cPlayer::MoveToWorld( const char* a_WorldName )
/* Remove all links to the old world */
m_World->RemovePlayer( this );
m_ClientHandle->RemoveFromAllChunks();
cChunkPtr Chunk = m_World->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
if ( Chunk != NULL )
{
Chunk->RemoveEntity( this );
Chunk->Broadcast( cPacket_DestroyEntity( this ) ); // Remove player entity from all clients in old world
}
m_World->RemoveEntityFromChunk(this, m_ChunkX, m_ChunkY, m_ChunkZ);
/* Add player to all the necessary parts of the new world */
SetWorld( World );
@ -831,11 +841,8 @@ bool cPlayer::LoadFromDisk()
return false;
}
// Get file size
long FileSize = f.GetSize();
std::auto_ptr<char> buffer(new char[FileSize]);
if (f.Read(buffer.get(), FileSize) != FileSize)
AString buffer;
if (f.ReadRestOfFile(buffer) != f.GetSize())
{
LOGERROR("ERROR READING FROM FILE \"%s\"", SourceFile.c_str());
return false;
@ -844,12 +851,10 @@ bool cPlayer::LoadFromDisk()
Json::Value root;
Json::Reader reader;
if (!reader.parse(buffer.get(), root, false))
if (!reader.parse(buffer, root, false))
{
LOGERROR("ERROR WHILE PARSING JSON FROM FILE %s", SourceFile.c_str());
}
buffer.reset();
Json::Value & JSON_PlayerPosition = root["position"];
if( JSON_PlayerPosition.size() == 3 )
@ -874,6 +879,10 @@ bool cPlayer::LoadFromDisk()
m_pState->LoadedWorldName = root.get("world", "world").asString();
LOGD("Player \"%s\" was read from file, spawning at {%.2f, %.2f, %.2f} in world \"%s\"",
m_pState->PlayerName.c_str(), m_Pos.x, m_Pos.y, m_Pos.z, m_pState->LoadedWorldName.c_str()
);
return true;
}

View File

@ -431,7 +431,12 @@ void cWorld::InitializeSpawn()
int ChunkX = 0, ChunkY = 0, ChunkZ = 0;
BlockToChunk( (int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ, ChunkX, ChunkY, ChunkZ );
// For the debugging builds, don't make the server build too much world upon start:
#ifdef _DEBUG
int ViewDist = 9;
#else
int ViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is
#endif // _DEBUG
LOG("Preparing spawn area in world \"%s\"", m_WorldName.c_str());
for (int x = 0; x < ViewDist; x++)
@ -807,16 +812,6 @@ void cWorld::GrowTree( int a_X, int a_Y, int a_Z )
void cWorld::UnloadUnusedChunks()
{
m_LastUnload = m_Time;
m_ChunkMap->UnloadUnusedChunks();
}
cChunkPtr cWorld::GetChunkOfBlock( int a_X, int a_Y, int a_Z )
{
int ChunkX, ChunkY, ChunkZ;
@ -1005,6 +1000,15 @@ void cWorld::Broadcast( const cPacket & a_Packet, cClientHandle* a_Exclude)
void cWorld::BroadcastToChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cPacket & a_Packet, cClientHandle * a_Exclude)
{
m_ChunkMap->BroadcastToChunk(a_ChunkX, a_ChunkY, a_ChunkZ, a_Packet, a_Exclude);
}
void cWorld::BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_Packet, cClientHandle * a_Exclude)
{
m_ChunkMap->BroadcastToChunkOfBlock(a_X, a_Y, a_Z, a_Packet, a_Exclude);
@ -1095,6 +1099,25 @@ bool cWorld::HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const
void cWorld::UnloadUnusedChunks(void )
{
m_LastUnload = m_Time;
m_ChunkMap->UnloadUnusedChunks();
}
void cWorld::CollectPickupsByPlayer(cPlayer * a_Player)
{
m_ChunkMap->CollectPickupsByPlayer(a_Player);
}
void cWorld::SetMaxPlayers(int iMax)
{
m_MaxPlayers = MAX_PLAYERS;
@ -1271,10 +1294,27 @@ bool cWorld::DoWithEntity( int a_UniqueID, cEntityCallback & a_Callback )
void cWorld::RemoveEntityFromChunk(cEntity * a_Entity)
void cWorld::RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ)
{
cChunkPtr Chunk = GetChunkOfBlock((int)(a_Entity->GetPosX()), (int)(a_Entity->GetPosY()), (int)(a_Entity->GetPosZ()));
Chunk->RemoveEntity(a_Entity);
m_ChunkMap->RemoveEntityFromChunk(a_Entity, a_ChunkX, a_ChunkY, a_ChunkZ);
}
void cWorld::MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ)
{
m_ChunkMap->MoveEntityToChunk(a_Entity, a_ChunkX, a_ChunkY, a_ChunkZ);
}
void cWorld::CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkY2, int a_ChunkZ2, cClientDiffCallback & a_Callback)
{
m_ChunkMap->CompareChunkClients(a_ChunkX1, a_ChunkY1, a_ChunkZ1, a_ChunkX2, a_ChunkY2, a_ChunkZ2, a_Callback);
}
@ -1286,7 +1326,6 @@ void cWorld::SaveAllChunks()
LOG("Saving all chunks...");
m_LastSave = m_Time;
m_ChunkMap->SaveAllChunks();
LOG("Done saving chunks");
}

View File

@ -68,6 +68,8 @@ public:
void Broadcast( const cPacket & a_Packet, cClientHandle* a_Exclude = 0 );
void BroadcastToChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cPacket & a_Packet, cClientHandle * a_Exclude = NULL);
void BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_Packet, cClientHandle * a_Exclude = NULL);
void MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
@ -80,6 +82,7 @@ public:
bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ) const;
bool HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const;
void UnloadUnusedChunks(void);
void CollectPickupsByPlayer(cPlayer * a_Player);
// MOTD
const AString & GetDescription(void) const {return m_Description; }
@ -105,7 +108,18 @@ public:
void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player
void AddEntity( cEntity* a_Entity );
void RemoveEntityFromChunk( cEntity * a_Entity);
/// Add an entity to the chunk specified; broadcasts the a_SpawnPacket to all clients of that chunk
void AddEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ, cPacket * a_SpawnPacket);
/// Removes the entity from the chunk specified
void RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ);
/// Moves the entity from its current chunk to the new chunk specified
void MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ);
/// Compares clients of two chunks, calls the callback accordingly
void CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkY2, int a_ChunkZ2, cClientDiffCallback & a_Callback);
// TODO: Export to Lua
bool DoWithEntity( int a_UniqueID, cEntityCallback & a_Callback );