From d592882fe0d1e7762470e6b5eff2b14ed26f1e69 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Mon, 20 Feb 2012 16:39:00 +0000 Subject: Removed some more cChunkPtr usage git-svn-id: http://mc-server.googlecode.com/svn/trunk@298 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/cChunk.cpp | 10 +++- source/cChunk.h | 26 ++++++++- source/cChunkGenerator.h | 3 +- source/cChunkMap.cpp | 144 +++++++++++++++++++++++++++++++++++++++++++++-- source/cChunkMap.h | 17 +++++- source/cClientHandle.cpp | 5 +- source/cEntity.cpp | 83 +++++++++++++++++---------- source/cEntity.h | 4 ++ source/cMonster.cpp | 36 ++++++------ source/cPawn.cpp | 10 +--- source/cPlayer.cpp | 65 ++++++++++++--------- source/cWorld.cpp | 67 +++++++++++++++++----- source/cWorld.h | 16 +++++- 13 files changed, 372 insertions(+), 114 deletions(-) diff --git a/source/cChunk.cpp b/source/cChunk.cpp index 827e97cb9..9f64716d0 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -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(); + } } } diff --git a/source/cChunk.h b/source/cChunk.h index 4453ed16a..289461f0d 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -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 cChunkPtr; diff --git a/source/cChunkGenerator.h b/source/cChunkGenerator.h index cb30636c3..de1b081d5 100644 --- a/source/cChunkGenerator.h +++ b/source/cChunkGenerator.h @@ -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 diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index 10577dc6f..6ae3fd987 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -6,6 +6,7 @@ #include "cWorld.h" #include "cRoot.h" #include "cMakeDir.h" +#include "cPlayer.h" #ifndef _WIN32 #include // abs @@ -15,9 +16,6 @@ #include -#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); diff --git a/source/cChunkMap.h b/source/cChunkMap.h index a9cb4d661..33e468eb1 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -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 ); diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index e3662f5ed..51cd31433 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -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; diff --git a/source/cEntity.cpp b/source/cEntity.cpp index 00faf5baa..49993c093 100644 --- a/source/cEntity.cpp +++ b/source/cEntity.cpp @@ -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 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 { diff --git a/source/cEntity.h b/source/cEntity.h index 84d9c766d..0165276b6 100644 --- a/source/cEntity.h +++ b/source/cEntity.h @@ -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 diff --git a/source/cMonster.cpp b/source/cMonster.cpp index 18baa6a87..6fa8561e5 100644 --- a/source/cMonster.cpp +++ b/source/cMonster.cpp @@ -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(); diff --git a/source/cPawn.cpp b/source/cPawn.cpp index ff4c957e8..ed16f57bb 100644 --- a/source/cPawn.cpp +++ b/source/cPawn.cpp @@ -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); } diff --git a/source/cPlayer.cpp b/source/cPlayer.cpp index f6a0d1fcc..495cc6abf 100644 --- a/source/cPlayer.cpp +++ b/source/cPlayer.cpp @@ -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 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; } diff --git a/source/cWorld.cpp b/source/cWorld.cpp index f5e40ec0b..83f36f1d5 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -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) +{ + 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) { - cChunkPtr Chunk = GetChunkOfBlock((int)(a_Entity->GetPosX()), (int)(a_Entity->GetPosY()), (int)(a_Entity->GetPosZ())); - Chunk->RemoveEntity(a_Entity); + 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"); } diff --git a/source/cWorld.h b/source/cWorld.h index a9c068336..8a1cf729d 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -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 ); -- cgit v1.2.3