diff --git a/VC2010/MCServer.vcxproj b/VC2010/MCServer.vcxproj index 1186a6b5c..4c0a3cca7 100644 --- a/VC2010/MCServer.vcxproj +++ b/VC2010/MCServer.vcxproj @@ -522,6 +522,7 @@ + diff --git a/VC2010/MCServer.vcxproj.filters b/VC2010/MCServer.vcxproj.filters index 203933c48..4ed54000a 100644 --- a/VC2010/MCServer.vcxproj.filters +++ b/VC2010/MCServer.vcxproj.filters @@ -448,6 +448,9 @@ {69e6a927-8e49-4d39-af88-f587d17bb8a3} + + {9bd7a65c-b60f-4905-ae2b-7c3c7586eaef} + @@ -1371,6 +1374,9 @@ cInventory\cSurvivalInventory + + !Smart_Pointers + 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 + m_pState->NumRefs--; + if( m_pState->NumRefs < 0 ) { - 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 ); - } + LOGWARN("WARNING: cChunk: Tried to remove reference, but the chunk is not referenced!"); } - else // No ID so add one to MinusReferences - { - 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); - } - } - 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