From 50a7722242197f9a3b4300e154c1e66d1177839a Mon Sep 17 00:00:00 2001 From: faketruth Date: Thu, 19 Jan 2012 18:12:39 +0000 Subject: 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 --- source/Vector3d.h | 2 ++ source/cChunk.cpp | 56 +++++++++++------------------------------------- source/cChunk.h | 4 ++-- source/cChunkMap.cpp | 2 +- source/cClientHandle.cpp | 34 ++++++++++++++++++++++++++++- source/cClientHandle.h | 1 + source/cEntity.cpp | 2 +- source/cPickup.cpp | 4 ++-- source/cServer.cpp | 3 +-- source/cWorld.cpp | 56 +++++++++++++++++++++++++----------------------- source/cWorld.h | 13 +++++------ source/ptr_cChunk.h | 37 ++++++++++++++++++++++++++++++++ 12 files changed, 129 insertions(+), 85 deletions(-) create mode 100644 source/ptr_cChunk.h (limited to 'source') diff --git a/source/Vector3d.h b/source/Vector3d.h index 84b04fce7..f93c2c763 100644 --- a/source/Vector3d.h +++ b/source/Vector3d.h @@ -22,6 +22,8 @@ public: //tolua_export inline double Dot( const Vector3d & a_V ) const { return x * a_V.x + y * a_V.y + z * a_V.z; } //tolua_export inline Vector3d Cross( const Vector3d & v ) const { return Vector3d( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x ); } //tolua_export + inline bool Equals( const Vector3d & v ) const { return (x == v.x && y == v.y && z == v.z ); } //tolua_export + void operator += ( const Vector3d& a_V ) { x += a_V.x; y += a_V.y; z += a_V.z; } void operator += ( Vector3d* a_V ) { x += a_V->x; y += a_V->y; z += a_V->z; } void operator -= ( const Vector3d& a_V ) { x -= a_V.x; y -= a_V.y; z -= a_V.z; } diff --git a/source/cChunk.cpp b/source/cChunk.cpp index 47e92555f..3af1b0ff3 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -62,6 +62,7 @@ struct cChunk::sChunkState sChunkState() : TotalReferencesEver( 0 ) , MinusReferences( 0 ) + , NumRefs( 0 ) {} FurnaceEntityList TickBlockEntities; @@ -79,6 +80,7 @@ struct cChunk::sChunkState ReferenceMap References; int MinusReferences; // References.size() - MinusReferences = Actual amount of references. This is due to removal of reference without an ID (don't know which to remove, so remove none) int TotalReferencesEver; // For creating a unique reference ID + int NumRefs; }; cChunk::~cChunk() @@ -541,8 +543,8 @@ void cChunk::SpreadLight(char* a_LightBuffer) bool bCalcLeft, bCalcRight, bCalcFront, bCalcBack; bCalcLeft = bCalcRight = bCalcFront = bCalcBack = false; // Spread to neighbour chunks X-axis - cChunk* LeftChunk = m_World->GetChunkUnreliable( m_PosX-1, m_PosY, m_PosZ ); - cChunk* RightChunk = m_World->GetChunkUnreliable( m_PosX+1, m_PosY, m_PosZ ); + ptr_cChunk LeftChunk = m_World->GetChunkUnreliable( m_PosX-1, m_PosY, m_PosZ ); + ptr_cChunk RightChunk = m_World->GetChunkUnreliable( m_PosX+1, m_PosY, m_PosZ ); char* LeftSky = 0, *RightSky = 0; if(LeftChunk) LeftSky = (a_LightBuffer==m_BlockSkyLight)?LeftChunk->pGetSkyLight():LeftChunk->pGetLight(); if(RightChunk) RightSky = (a_LightBuffer==m_BlockSkyLight)?RightChunk->pGetSkyLight():RightChunk->pGetLight(); @@ -579,8 +581,8 @@ void cChunk::SpreadLight(char* a_LightBuffer) } // Spread to neighbour chunks Z-axis - cChunk* FrontChunk = m_World->GetChunkUnreliable( m_PosX, m_PosY, m_PosZ-1 ); - cChunk* BackChunk = m_World->GetChunkUnreliable( m_PosX, m_PosY, m_PosZ+1 ); + ptr_cChunk FrontChunk = m_World->GetChunkUnreliable( m_PosX, m_PosY, m_PosZ-1 ); + ptr_cChunk BackChunk = m_World->GetChunkUnreliable( m_PosX, m_PosY, m_PosZ+1 ); char* FrontSky = 0, *BackSky = 0; if(FrontChunk) FrontSky = (a_LightBuffer==m_BlockSkyLight)?FrontChunk->pGetSkyLight():FrontChunk->pGetLight(); if(BackChunk) BackSky = (a_LightBuffer==m_BlockSkyLight)?BackChunk->pGetSkyLight():BackChunk->pGetLight(); @@ -1177,60 +1179,28 @@ void cChunk::PositionToWorldPosition(int a_ChunkX, int a_ChunkY, int a_ChunkZ, i a_Z = m_PosZ * 16 + a_ChunkZ; } -int cChunk::AddReference( const char* a_Info /* = 0 */ ) +void cChunk::AddReference() { m_pState->ReferenceCriticalSection.Lock(); - - m_pState->TotalReferencesEver++; - - std::string Info; - if( a_Info ) Info = a_Info; - - m_pState->References[ m_pState->TotalReferencesEver ] = Info; - - int ID = m_pState->TotalReferencesEver; + m_pState->NumRefs++; m_pState->ReferenceCriticalSection.Unlock(); - return ID; } -void cChunk::RemoveReference( int a_ID ) +void cChunk::RemoveReference() { m_pState->ReferenceCriticalSection.Lock(); - - if( a_ID > -1 ) // Remove reference with an ID - { - bool bFound = false; - for( ReferenceMap::iterator itr = m_pState->References.begin(); itr != m_pState->References.end(); ++itr ) - { - if( itr->first == a_ID ) - { - bFound = true; - m_pState->References.erase( itr ); - break; - } - } - - if( !bFound ) - { - LOGWARN("WARNING: cChunk: Tried to remove reference %i but it could not be found! May cause memory leak", a_ID ); - } - } - else // No ID so add one to MinusReferences + m_pState->NumRefs--; + if( m_pState->NumRefs < 0 ) { - m_pState->MinusReferences++; - if( (int)m_pState->References.size() - m_pState->MinusReferences < 0 ) - { - LOGWARN("WARNING: cChunk: Tried to remove reference %i, but the chunk is not referenced!", a_ID); - } + LOGWARN("WARNING: cChunk: Tried to remove reference, but the chunk is not referenced!"); } - m_pState->ReferenceCriticalSection.Unlock(); } int cChunk::GetReferenceCount() { m_pState->ReferenceCriticalSection.Unlock(); - int Refs = (int)m_pState->References.size() - m_pState->MinusReferences; + int Refs = m_pState->NumRefs; m_pState->ReferenceCriticalSection.Lock(); return Refs; } diff --git a/source/cChunk.h b/source/cChunk.h index 8555e01cf..15577d372 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -102,8 +102,8 @@ public: static const int c_BlockDataSize = c_NumBlocks * 2 + (c_NumBlocks/2); // 2.5 * numblocks // Reference counting - int AddReference( const char* a_Info = 0 ); // a_Info is for debugging - void RemoveReference( int a_ID = -1 ); + void AddReference(); + void RemoveReference(); int GetReferenceCount(); private: struct sChunkState; diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index d05fd4a43..fb23096d8 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -465,7 +465,7 @@ void cChunkMap::UnloadUnusedChunks() if( Chunk && Chunk->GetClients().size() == 0 && Chunk->GetReferenceCount() <= 0 ) { Chunk->SaveToDisk(); - World->RemoveSpread( Chunk ); + World->RemoveSpread( ptr_cChunk( Chunk ) ); RemoveChunk( Chunk ); delete Chunk; } diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index 891140630..46669848e 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -113,6 +113,8 @@ struct cClientHandle::sClientHandleState cCriticalSection SocketCriticalSection; cSemaphore* pSemaphore; + Vector3d ConfirmPosition; + cPacket* PacketMap[256]; }; @@ -126,6 +128,7 @@ cClientHandle::cClientHandle(const cSocket & a_Socket) , m_bSendLoginResponse( false ) , m_pState( new sClientHandleState ) , m_Ping(1000) + , m_bPositionConfirmed( false ) { LOG("cClientHandle::cClientHandle"); @@ -382,6 +385,7 @@ void cClientHandle::StreamChunksSmart( cChunk** a_Chunks, unsigned int a_NumChun { a_Chunks[ClosestIdx]->Send( this ); a_Chunks[ClosestIdx]->AddClient( this ); + //LOGINFO("CCC: Sending chunk %i %i", a_Chunks[ClosestIdx]->GetPosX(), a_Chunks[ClosestIdx]->GetPosZ() ); a_Chunks[ClosestIdx] = 0; } } @@ -526,6 +530,7 @@ void cClientHandle::HandlePacket( cPacket* a_Packet ) StreamChunks(); // Send position + m_pState->ConfirmPosition = m_Player->GetPosition(); Send( cPacket_PlayerMoveLook( m_Player ) ); } break; @@ -539,7 +544,32 @@ void cClientHandle::HandlePacket( cPacket* a_Packet ) break; } } - else // m_bLoggedIn == true + else if( !m_bPositionConfirmed ) // m_bLoggedIn == true + { + switch( a_Packet->m_PacketID ) + { + case E_PLAYERMOVELOOK: + { + cPacket_PlayerMoveLook* PacketData = reinterpret_cast(a_Packet); + Vector3d ReceivedPosition = Vector3d( PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ ); + + // Test the distance between points with a small/large enough value instead of comparing directly. Floating point inaccuracies might screw stuff up + if( ( ReceivedPosition - m_pState->ConfirmPosition ).SqrLength() < 1.0 ) + { + // Test + if( ReceivedPosition.Equals( m_pState->ConfirmPosition ) ) + { + LOGINFO("Exact position confirmed by client!"); + } + m_bPositionConfirmed = true; + } + } + break; + } + + } + + if( m_bPositionConfirmed ) { switch( a_Packet->m_PacketID ) { @@ -1434,6 +1464,7 @@ void cClientHandle::SendThread( void *lpParam ) m_pState->SocketCriticalSection.Unlock(); break; } + //LOG("Send packet: 0x%2x", Packet->m_PacketID ); bool bSuccess = Packet->Send( m_pState->Socket ); m_pState->SocketCriticalSection.Unlock(); if( !bSuccess ) @@ -1481,6 +1512,7 @@ void cClientHandle::ReceiveThread( void *lpParam ) } else { + //LOG("Recv packet: 0x%2x", (unsigned char)temp ); cPacket* pPacket = self->m_pState->PacketMap[ (unsigned char)temp ]; if( pPacket ) { diff --git a/source/cClientHandle.h b/source/cClientHandle.h index 6f3e3ddc0..0011903b1 100644 --- a/source/cClientHandle.h +++ b/source/cClientHandle.h @@ -78,6 +78,7 @@ private: static const unsigned short PING_TIME_MS = 1000; //minecraft sends 1 per 20 ticks (1 second or every 1000 ms) bool m_bLoggedIn; + bool m_bPositionConfirmed; bool m_bSendLoginResponse; bool m_bKeepThreadGoing; diff --git a/source/cEntity.cpp b/source/cEntity.cpp index ce7117498..8a841ea87 100644 --- a/source/cEntity.cpp +++ b/source/cEntity.cpp @@ -148,7 +148,7 @@ void cEntity::RemoveFromChunk( cChunk* a_Chunk ) { if( m_World ) { - cChunk* Chunk = ( a_Chunk ? a_Chunk : m_World->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ ) ); + cChunk* Chunk = ( a_Chunk ? a_Chunk : (cChunk*)m_World->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ ) ); if( Chunk ) { cPacket_DestroyEntity DestroyEntity( this ); diff --git a/source/cPickup.cpp b/source/cPickup.cpp index c665577f0..9e9dc2666 100644 --- a/source/cPickup.cpp +++ b/source/cPickup.cpp @@ -197,7 +197,7 @@ void cPickup::HandlePhysics(float a_Dt) Direction WaterDir = World->GetWaterSimulator()->GetFlowingDirection((int) m_Pos->x - 1, (int) m_Pos->y, (int) m_Pos->z - 1); - *m_WaterSpeed *= 0.9; //Keep old speed but lower it + *m_WaterSpeed *= 0.9f; //Keep old speed but lower it switch(WaterDir) { @@ -256,7 +256,7 @@ void cPickup::HandlePhysics(float a_Dt) } } *m_Pos = Tracer.RealHit; - *m_Pos += *Tracer.HitNormal * 0.2; + *m_Pos += *Tracer.HitNormal * 0.2f; } else diff --git a/source/cServer.cpp b/source/cServer.cpp index d3e8e43a7..dc4b5b5c9 100644 --- a/source/cServer.cpp +++ b/source/cServer.cpp @@ -277,7 +277,7 @@ void cServer::StartListenClient() bool cServer::Tick(float a_Dt) { - //LOG("Tick"); + //LOG("1. Tick"); if( a_Dt > 100.f ) a_Dt = 100.f; // Don't go over 1/10 second cSleep::MilliSleep( 50 ); // Don't tick too much @@ -289,7 +289,6 @@ bool cServer::Tick(float a_Dt) m_Millisecondsf = m_Millisecondsf - (int)m_Millisecondsf; } - cRoot::Get()->TickWorlds( a_Dt ); // TODO - Maybe give all worlds their own thread? //World->LockClientHandle(); // TODO - Lock client list diff --git a/source/cWorld.cpp b/source/cWorld.cpp index d10d01a0d..fc7447c1d 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -45,6 +45,8 @@ #include "packets/cPacket_NewInvalidState.h" #include "packets/cPacket_Thunderbolt.h" +#include "ptr_cChunk.h" + #include "Vector3d.h" #include @@ -430,12 +432,11 @@ void cWorld::Tick(float a_Dt) int TimesSpreaded = 0; while( !m_pState->SpreadQueue.empty() && TimesSpreaded < 50 ) // Spread a max of 50 times each tick, otherwise server will hang { - cChunk* Chunk = (*m_pState->SpreadQueue.begin()); + ptr_cChunk& Chunk = *m_pState->SpreadQueue.begin(); //LOG("Spreading: %p", Chunk ); Chunk->SpreadLight( Chunk->pGetSkyLight() ); Chunk->SpreadLight( Chunk->pGetLight() ); m_pState->SpreadQueue.remove( Chunk ); - Chunk->RemoveReference(); TimesSpreaded++; } if( TimesSpreaded >= 50 ) @@ -494,7 +495,7 @@ void cWorld::Tick(float a_Dt) FastSetBlock( SetBlockData.x, SetBlockData.y, SetBlockData.z, SetBlockData.BlockID, SetBlockData.BlockMeta ); // If unable to set block, it's added to FastSetBlockQueue again } if( FastSetBlockQueueCopy.size() != m_pState->FastSetBlockQueue.size() ) - LOG(" Before: %i, after %i" , FastSetBlockQueueCopy.size(), m_pState->FastSetBlockQueue.size() ); + LOG(" Before: %i, after %i" , FastSetBlockQueueCopy.size(), m_pState->FastSetBlockQueue.size() ); if( m_Time - m_LastSave > 60*5 ) // Save each 5 minutes { @@ -712,20 +713,36 @@ cChunk* cWorld::GetChunk( int a_X, int a_Y, int a_Z ) cChunk* Chunk = GetChunkUnreliable( a_X, a_Y, a_Z ); if( Chunk ) return Chunk; +#if 1 // Current thread chunk generation + + // Found nothing, create a chunk + Chunk = new cChunk( a_X, a_Y, a_Z, this ); + if(Chunk) + { + LOGWARN("Created new chunk! %i %i", a_X, a_Z); + LockChunks(); + m_ChunkMap->AddChunk( Chunk ); + UnlockChunks(); + Chunk->Initialize(); + return Chunk; + } + return 0; +#else // Async thread generation + // Generate new chunk asynchronously m_pState->pChunkGenerator->GenerateChunk( a_X, a_Z ); // Could not find chunk, it's being generated, so return 0 return 0; +#endif } -cChunk* cWorld::GetChunkUnreliable( int a_X, int a_Y, int a_Z ) +ptr_cChunk cWorld::GetChunkUnreliable( int a_X, int a_Y, int a_Z ) { LockChunks(); - cChunk* Chunk = m_ChunkMap->GetChunk( a_X, a_Y, a_Z ); + ptr_cChunk Chunk( m_ChunkMap->GetChunk( a_X, a_Y, a_Z ) ); UnlockChunks(); - if( Chunk ) return Chunk; - return 0; + return Chunk; } cChunk* cWorld::GetChunkOfBlock( int a_X, int a_Y, int a_Z ) @@ -761,18 +778,6 @@ void cWorld::FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_B return; } - // Could not find chunk, so it has been pushed into the generate chunks queue - // Check if currently generating the target chunk - m_pState->pChunkGenerator->Lock(); - Chunk = m_pState->pChunkGenerator->GetCurrentlyGenerating(); - if( Chunk && Chunk->GetPosX() == ChunkX && Chunk->GetPosZ() == ChunkZ ) - { - Chunk->FastSetBlock(X, Y, Z, a_BlockType, a_BlockMeta ); - m_pState->pChunkGenerator->Unlock(); - return; - } - m_pState->pChunkGenerator->Unlock(); - // Unable to set block right now, try again later m_pState->FastSetBlockQueue.push_back( sSetBlockData( a_X, a_Y, a_Z, a_BlockType, a_BlockMeta ) ); } @@ -1052,23 +1057,20 @@ void cWorld::UnlockChunks() m_ChunksCriticalSection->Unlock(); } -void cWorld::ReSpreadLighting( cChunk* a_Chunk ) +void cWorld::ReSpreadLighting( const ptr_cChunk& a_Chunk ) { LockChunks(); - m_pState->SpreadQueue.remove( a_Chunk ); + m_pState->SpreadQueue.remove( a_Chunk ); m_pState->SpreadQueue.push_back( a_Chunk ); -#define STRINGIZE(x) #x - a_Chunk->AddReference( __FILE__ ": " STRINGIZE(__LINE__) ); + //#define STRINGIZE(x) #x + //a_Chunk->AddReference( __FILE__ ": " STRINGIZE(__LINE__) ); UnlockChunks(); } -void cWorld::RemoveSpread( cChunk* a_Chunk ) +void cWorld::RemoveSpread( const ptr_cChunk& a_Chunk ) { LockChunks(); - size_t SizeBefore = m_pState->SpreadQueue.size(); m_pState->SpreadQueue.remove( a_Chunk ); - if( SizeBefore != m_pState->SpreadQueue.size() ) - a_Chunk->RemoveReference(); UnlockChunks(); } diff --git a/source/cWorld.h b/source/cWorld.h index ab99c11b1..38b7ec349 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -13,6 +13,7 @@ enum ENUM_ITEM_ID; #include #include "cSimulatorManager.h" +#include "ptr_cChunk.h" class cPacket; class cRedstone; @@ -36,7 +37,7 @@ class cWorld //tolua_export public: typedef std::list< cClientHandle* > ClientList; typedef std::list< cEntity* > EntityList; - typedef std::list< cChunk* > ChunkList; + typedef std::list< ptr_cChunk > ChunkList; typedef std::list< cPlayer* > PlayerList; std::vector m_RSList; @@ -56,7 +57,7 @@ public: cChunk* GetChunk( int a_X, int a_Y, int a_Z ); cChunk* GetChunkReliable( int a_X, int a_Y, int a_Z ); - cChunk* GetChunkUnreliable( int a_X, int a_Y, int a_Z ); + ptr_cChunk GetChunkUnreliable( int a_X, int a_Y, int a_Z ); cChunk* GetChunkOfBlock( int a_X, int a_Y, int a_Z ); char GetHeight( int a_X, int a_Z ); //tolua_export @@ -148,14 +149,14 @@ public: void LockChunks(); void UnlockChunks(); - void ReSpreadLighting( cChunk* a_Chunk ); - void RemoveSpread( cChunk* a_Chunk ); + void ReSpreadLighting( const ptr_cChunk& a_Chunk ); + void RemoveSpread( const ptr_cChunk& a_Chunk ); void InitializeSpawn(); - void CastThunderbolt ( int, int, int ); //tolua_export + void CastThunderbolt ( int, int, int ); //tolua_export void SetWeather ( int ); //tolua_export - int GetWeather() { return m_Weather; }; //tolua_export + int GetWeather() { return m_Weather; }; //tolua_export cWorldGenerator* GetWorldGenerator() { return m_WorldGenerator; } private: diff --git a/source/ptr_cChunk.h b/source/ptr_cChunk.h new file mode 100644 index 000000000..c3556839c --- /dev/null +++ b/source/ptr_cChunk.h @@ -0,0 +1,37 @@ +#pragma once + +#include "cChunk.h" + +class ptr_cChunk +{ +public: + ptr_cChunk( cChunk* a_Ptr ) + : m_Ptr( a_Ptr ) + { + if( m_Ptr ) m_Ptr->AddReference(); + } + + ptr_cChunk( const ptr_cChunk& a_Clone ) + : m_Ptr( a_Clone.m_Ptr ) + { + if( m_Ptr ) m_Ptr->AddReference(); + } + + ~ptr_cChunk() + { + if( m_Ptr ) m_Ptr->RemoveReference(); + } + + cChunk* operator-> () + { + return m_Ptr; + } + + cChunk& operator* () { return *m_Ptr; } + bool operator!() { return !m_Ptr; } + bool operator==( const ptr_cChunk& a_Other ) { return m_Ptr == a_Other.m_Ptr; } + operator bool() { return m_Ptr != 0; } + operator cChunk*() { return m_Ptr; } +private: + cChunk* m_Ptr; +}; \ No newline at end of file -- cgit v1.2.3