From c51a4b9469fee0314d1b849206d1cf1c7c1240e4 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Tue, 10 Apr 2012 11:22:11 +0000 Subject: Added the "/regeneratechunk" command that regenerates either current chunk or a chunk specified with x, z parameters. TODO: permissions - we don't want guests erasing our chunks! git-svn-id: http://mc-server.googlecode.com/svn/trunk@454 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/cChunk.cpp | 44 +++++++++++++++----------------------------- source/cChunk.h | 5 +++-- source/cChunkGenerator.cpp | 6 ++++-- source/cChunkMap.cpp | 17 ++++++++++++++++- source/cChunkMap.h | 3 +++ source/cClientHandle.cpp | 17 ++++++++++++++++- source/cClientHandle.h | 3 +++ source/cServer.cpp | 29 ++++++++++++++++++++++++++++- source/cWorld.cpp | 12 ++++++++++++ source/cWorld.h | 5 ++++- 10 files changed, 104 insertions(+), 37 deletions(-) diff --git a/source/cChunk.cpp b/source/cChunk.cpp index 54fbf4b94..597568a76 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -67,11 +67,11 @@ sSetBlock::sSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockM /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cChunk: -cChunk::cChunk(int a_X, int a_Y, int a_Z, cChunkMap * a_ChunkMap, cWorld * a_World) +cChunk::cChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkMap * a_ChunkMap, cWorld * a_World) : m_bCalculateLighting( false ) - , m_PosX( a_X ) - , m_PosY( a_Y ) - , m_PosZ( a_Z ) + , m_PosX( a_ChunkX ) + , m_PosY( a_ChunkY ) + , m_PosZ( a_ChunkZ ) , m_BlockTickNum( 0 ) , m_BlockTickX( 0 ) , m_BlockTickY( 0 ) @@ -121,38 +121,24 @@ cChunk::~cChunk() -void cChunk::SetValid(bool a_SendToClients) +void cChunk::SetValid(void) { m_IsValid = true; m_World->GetChunkMap()->ChunkValidated(); - - if (!a_SendToClients) - { - return; - } - - if (m_LoadedByClient.empty()) - { - return; - } - - // Sending the chunk here interferes with the lighting done in the tick thread and results in the "invalid compressed data" on the client - /* - cPacket_PreChunk PreChunk; - PreChunk.m_PosX = m_PosX; - PreChunk.m_PosZ = m_PosZ; - PreChunk.m_bLoad = true; - cPacket_MapChunk MapChunk(this); - Broadcast(&PreChunk); - Broadcast(&MapChunk); - - // Let all clients of this chunk know that it has been already sent to the client +} + + + + + +void cChunk::MarkRegenerating(void) +{ + // Tell all clients attached to this chunk that they want this chunk: for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr) { - (*itr)->ChunkJustSent(this); + (*itr)->AddWantedChunk(m_PosX, m_PosZ); } // for itr - m_LoadedByClient[] - */ } diff --git a/source/cChunk.h b/source/cChunk.h index cb72ef594..f829341e5 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -51,11 +51,12 @@ class cChunk : public cChunkDef // The inheritance is "misused" here only to inherit the functions and constants defined in cChunkDef { public: - cChunk(int a_X, int a_Y, int a_Z, cChunkMap * a_ChunkMap, cWorld * a_World); + cChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkMap * a_ChunkMap, cWorld * a_World); ~cChunk(); bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk is valid (loaded / generated) - void SetValid(bool a_SendToClients = true); // Also wakes up all clients attached to this chunk to let them finish logging in + void SetValid(void); // Also wakes up any calls to cChunkMap::GetHeight() + void MarkRegenerating(void); // Marks all clients attached to this chunk as wanting this chunk bool IsDirty(void) const {return m_IsDirty; } // Returns true if the chunk has changed since it was last saved bool HasLoadFailed(void) const {return m_HasLoadFailed; } // Returns true if the chunk failed to load and hasn't been generated since then bool CanUnload(void); diff --git a/source/cChunkGenerator.cpp b/source/cChunkGenerator.cpp index fdfdeab46..67b004a69 100644 --- a/source/cChunkGenerator.cpp +++ b/source/cChunkGenerator.cpp @@ -155,15 +155,17 @@ void cChunkGenerator::Execute(void) Lock.Unlock(); // Unlock ASAP m_evtRemoved.Set(); - if (m_World->IsChunkValid(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ)) + // Hack for regenerating chunks: if Y != 0, the chunk is considered invalid, even if it has its data set + if ((coords.m_ChunkY == 0) && m_World->IsChunkValid(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ)) { + LOGD("Chunk [%d, %d] already generated, skipping generation", coords.m_ChunkX, coords.m_ChunkZ); // Already generated, ignore request continue; } if (SkipEnabled && !m_World->HasChunkAnyClients(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ)) { - LOGWARNING("Chunk generator overloaded, skipping chunk [%d, %d, %d] (HasClients: %d)", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); + LOGWARNING("Chunk generator overloaded, skipping chunk [%d, %d, %d]", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); continue; } diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index e01899f28..58cdd6f07 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -897,6 +897,22 @@ void cChunkMap::ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay) +void cChunkMap::MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + if (Chunk == NULL) + { + // Not present + return; + } + Chunk->MarkRegenerating(); +} + + + + + void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom ) { cCSLock Lock(m_CSLayers); @@ -971,7 +987,6 @@ cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkY, int a_Ch const int LocalX = a_ChunkX - m_LayerX * LAYER_SIZE; const int LocalZ = a_ChunkZ - m_LayerZ * LAYER_SIZE; - if (!((LocalX < LAYER_SIZE) && (LocalZ < LAYER_SIZE) && (LocalX > -1) && (LocalZ > -1))) { ASSERT(!"Asking a cChunkLayer for a chunk that doesn't belong to it!"); diff --git a/source/cChunkMap.h b/source/cChunkMap.h index ea93db80b..4364b421d 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -127,6 +127,9 @@ public: /// Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable; to be used only by cChunkStay! void ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay = true); + + /// Marks the chunk as being regenerated - all its clients want that chunk again (used by cWorld::RegenerateChunk() ) + void MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ); void Tick( float a_Dt, MTRand & a_TickRand ); diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index 7ec5e9834..0e9fd76b7 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -1708,9 +1708,9 @@ void cClientHandle::Send(const cPacket & a_Packet, ENUM_PRIORITY a_Priority /* = } } - // Check chunks being sent, erase them from m_ChunksToSend: if (a_Packet.m_PacketID == E_MAP_CHUNK) { + // Check chunks being sent, erase them from m_ChunksToSend: int ChunkX = ((cPacket_MapChunk &)a_Packet).m_PosX; int ChunkZ = ((cPacket_MapChunk &)a_Packet).m_PosZ; bool Found = false; @@ -1727,6 +1727,7 @@ void cClientHandle::Send(const cPacket & a_Packet, ENUM_PRIORITY a_Priority /* = } // for itr - m_ChunksToSend[] if (!Found) { + LOGD("Refusing to send chunk [%d, %d] - no longer wanted by client \"%s\".", ChunkX, ChunkZ, m_Username.c_str()); return; } } @@ -1858,6 +1859,20 @@ bool cClientHandle::WantsSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cClientHandle::AddWantedChunk(int a_ChunkX, int a_ChunkZ) +{ + LOGD("Adding chunk [%d, %d] to wanted chunks for client %p", a_ChunkX, a_ChunkZ, this); + cCSLock Lock(m_CSChunkLists); + if (std::find(m_ChunksToSend.begin(), m_ChunksToSend.end(), cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)) == m_ChunksToSend.end()) + { + m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)); + } +} + + + + + void cClientHandle::DataReceived(const char * a_Data, int a_Size) { // Data is received from the client diff --git a/source/cClientHandle.h b/source/cClientHandle.h index 69c3f3ae3..05ec39f07 100644 --- a/source/cClientHandle.h +++ b/source/cClientHandle.h @@ -111,6 +111,9 @@ public: /// Returns true if the client wants the chunk specified to be sent (in m_ChunksToSend) bool WantsSendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + + /// Adds the chunk specified to the list of chunks wanted for sending (m_ChunksToSend) + void AddWantedChunk(int a_ChunkX, int a_ChunkZ); private: diff --git a/source/cServer.cpp b/source/cServer.cpp index 23fcbdda0..eff4e9fc0 100644 --- a/source/cServer.cpp +++ b/source/cServer.cpp @@ -485,13 +485,40 @@ bool cServer::Command( cClientHandle & a_Client, const char* a_Cmd ) { if (split.size() != 2) { - a_Client.Send(cPacket_Chat(cChatColor::Green + "Invalid syntax, expected 1 parameter, the numebr of chunks to stream")); + a_Client.Send(cPacket_Chat(cChatColor::Green + "Invalid syntax, expected 1 parameter, the number of chunks to stream")); return false; } int dist = atol(split[1].c_str()); a_Client.SetViewDistance(dist); return true; } + + if (split[0].compare("/regeneratechunk") == 0) + { + int ChunkX, ChunkZ; + if (split.size() == 1) + { + // Regenerate current chunk + ChunkX = a_Client.GetPlayer()->GetChunkX(); + ChunkZ = a_Client.GetPlayer()->GetChunkZ(); + } + else if (split.size() == 3) + { + // Regenerate chunk in params + ChunkX = atoi(split[1].c_str()); + ChunkZ = atoi(split[2].c_str()); + } + else + { + a_Client.Send(cPacket_Chat(cChatColor::Green + "Invalid syntax, expected either 0 (current chunk) or 2 (x, z) parameters")); + return false; + } + AString Msg; + Printf(Msg, "Regenerating chunk [%d, %d]", ChunkX, ChunkZ); + a_Client.Send(cPacket_Chat(cChatColor::Green + Msg)); + a_Client.GetPlayer()->GetWorld()->RegenerateChunk(ChunkX, ChunkZ); + return true; + } return false; } diff --git a/source/cWorld.cpp b/source/cWorld.cpp index 266d425e4..a2c651d44 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -1426,6 +1426,18 @@ void cWorld::ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay) +void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ) +{ + m_ChunkMap->MarkChunkRegenerating(a_ChunkX, a_ChunkZ); + + // Trick: use Y=1 to force the chunk generation even though the chunk data is already present + m_Generator.GenerateChunk(a_ChunkX, 1, a_ChunkZ); +} + + + + + void cWorld::SaveAllChunks() { LOG("Saving all chunks..."); diff --git a/source/cWorld.h b/source/cWorld.h index a8591af65..29b7fce72 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -175,6 +175,9 @@ public: /// Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable. To be used only by cChunkStay! void ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay = true); + + /// Regenerate the given chunk: + void RegenerateChunk(int a_ChunkX, int a_ChunkZ); // TODO: Export to Lua bool DoWithEntity( int a_UniqueID, cEntityCallback & a_Callback ); @@ -324,7 +327,7 @@ private: AString m_WorldName; AString m_IniFileName; - + cWorld(const AString & a_WorldName); ~cWorld(); -- cgit v1.2.3