summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/cChunk.cpp44
-rw-r--r--source/cChunk.h5
-rw-r--r--source/cChunkGenerator.cpp6
-rw-r--r--source/cChunkMap.cpp17
-rw-r--r--source/cChunkMap.h3
-rw-r--r--source/cClientHandle.cpp17
-rw-r--r--source/cClientHandle.h3
-rw-r--r--source/cServer.cpp29
-rw-r--r--source/cWorld.cpp12
-rw-r--r--source/cWorld.h5
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();