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
master
faketruth 2012-01-19 18:12:39 +00:00
parent f47c852186
commit 50a7722242
14 changed files with 136 additions and 85 deletions

View File

@ -522,6 +522,7 @@
<ClInclude Include="..\source\packets\cPacket_WindowClick.h" />
<ClInclude Include="..\source\packets\cPacket_WindowClose.h" />
<ClInclude Include="..\source\packets\cPacket_WindowOpen.h" />
<ClInclude Include="..\source\ptr_cChunk.h" />
<ClInclude Include="..\source\SquirrelBindings.h" />
<ClInclude Include="..\source\Vector3d.h" />
<ClInclude Include="..\source\Vector3f.h" />

View File

@ -448,6 +448,9 @@
<Filter Include="cInventory\cCreativeInventory">
<UniqueIdentifier>{69e6a927-8e49-4d39-af88-f587d17bb8a3}</UniqueIdentifier>
</Filter>
<Filter Include="!Smart_Pointers">
<UniqueIdentifier>{9bd7a65c-b60f-4905-ae2b-7c3c7586eaef}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\source\cServer.cpp">
@ -1371,6 +1374,9 @@
<ClInclude Include="..\source\cSurvivalInventory.h">
<Filter>cInventory\cSurvivalInventory</Filter>
</ClInclude>
<ClInclude Include="..\source\ptr_cChunk.h">
<Filter>!Smart_Pointers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\source\AllToLua.pkg">

View File

@ -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; }

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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<cPacket_PlayerMoveLook*>(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 )
{

View File

@ -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;

View File

@ -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 );

View File

@ -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

View File

@ -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

View File

@ -45,6 +45,8 @@
#include "packets/cPacket_NewInvalidState.h"
#include "packets/cPacket_Thunderbolt.h"
#include "ptr_cChunk.h"
#include "Vector3d.h"
#include <time.h>
@ -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();
}

View File

@ -13,6 +13,7 @@ enum ENUM_ITEM_ID;
#include <string>
#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<int> 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:

37
source/ptr_cChunk.h Normal file
View File

@ -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;
};