@@ -28,7 +28,10 @@ namespace tsom
2828
2929 ServerPlanetEnvironment::ServerPlanetEnvironment (ServerInstance& serverInstance, std::optional<Nz::UInt32> databaseId, std::string generatorName, Nz::UInt32 seed, const Nz::Vector3ui& chunkCount, float cellSize, float cornerRadius) :
3030 ServerEnvironment (serverInstance, ServerEnvironmentType::Planet, true ),
31- m_databaseId (databaseId)
31+ m_databaseId (databaseId),
32+ m_generatorName (std::move(generatorName)),
33+ m_generationSeed (seed),
34+ m_chunkCount (chunkCount)
3235 {
3336 m_world->GetRegistry ().ctx ().emplace <ServerPlanetEnvironment*>(this );
3437 m_world->AddSystem <EnvironmentSwitchSystem>();
@@ -49,31 +52,20 @@ namespace tsom
4952 planetClass->InitAndActivateEntity (m_planetEntity);
5053
5154 auto & planetComponent = m_planetEntity.get <PlanetComponent>();
52- planetComponent.planet ->AddChunks (blockLibrary, chunkCount);
5355
54- if (m_databaseId)
55- LoadChunksFromDatabase ();
56-
57- auto & app = serverInstance.GetApplication ();
58- auto & taskScheduler = app.GetComponent <Nz::TaskSchedulerAppComponent>();
59-
60- planetComponent.planet ->GenerateChunks (blockLibrary, taskScheduler, seed, chunkCount, std::move (generatorName));
61- taskScheduler.WaitForTasks ();
62-
63- planetComponent.planet ->GeneratePlatform (blockLibrary, Direction::Right, { 65 , -18 , -39 });
64- planetComponent.planet ->GeneratePlatform (blockLibrary, Direction::Back, { -34 , 2 , 53 });
65- planetComponent.planet ->GeneratePlatform (blockLibrary, Direction::Front, { 22 , -35 , -59 });
66- planetComponent.planet ->GeneratePlatform (blockLibrary, Direction::Down, { 23 , -62 , 26 });
56+ m_chunkLoadingData = std::make_shared<ChunkLoadingData>();
57+ m_chunkLoadingData->chunkCount = m_chunkCount;
58+ m_chunkLoadingData->planet = planetComponent.planet ;
59+ m_chunkLoadingData->remainingChunks .emplace (-int (m_chunkCount.x / 2 ), -int (m_chunkCount.y / 2 ), -int (m_chunkCount.z / 2 ));
6760
68- std::size_t emptyChunkCount = 0 ;
69- planetComponent.planet ->ForEachChunk ([&](const ChunkIndices& /* osef*/ , const Chunk& chunk)
70- {
71- emptyChunkCount += chunk.GetBlockCount (EmptyBlockIndex);
72- });
61+ // planetComponent.planet->GeneratePlatform(blockLibrary, Direction::Right, { 65, -18, -39 });
62+ // planetComponent.planet->GeneratePlatform(blockLibrary, Direction::Back, { -34, 2, 53 });
63+ // planetComponent.planet->GeneratePlatform(blockLibrary, Direction::Front, { 22, -35, -59 });
64+ // planetComponent.planet->GeneratePlatform(blockLibrary, Direction::Down, { 23, -62, 26 });
7365
7466 // We want the player to be able to breathe 5s per empty block count
7567 // the player breathe 100ml per second
76- Nz::UInt64 oxygenAmount = Constants::SecondsToEmptyOxygenBlock * Nz::UInt64 (Constants::PlayerOxygenConsumption) * emptyChunkCount ;
68+ Nz::UInt64 oxygenAmount = Constants::SecondsToEmptyOxygenBlock * Nz::UInt64 (Constants::PlayerOxygenConsumption) * m_chunkCount. x * m_chunkCount. y * m_chunkCount. z ;
7769 m_atmosphere.SetGasAmount (GasType::Oxygen, oxygenAmount);
7870
7971 // We also want oxygen to be 21% of the atmosphere and have the rest as nitrogen
@@ -213,6 +205,73 @@ namespace tsom
213205 databaseSystem->Save ();
214206 }
215207
208+ void ServerPlanetEnvironment::OnTick (Nz::Time elapsedTime)
209+ {
210+ ServerEnvironment::OnTick (elapsedTime);
211+
212+ std::unique_lock lock (m_chunkLoadingData->mutex );
213+
214+ if (!m_chunkLoadingData->remainingChunks .empty ())
215+ {
216+ ChunkIndices indices = m_chunkLoadingData->remainingChunks .front ();
217+ m_chunkLoadingData->remainingChunks .pop ();
218+
219+ spdlog::debug (" loading chunk {};{};{} ({} remaining)\n " , indices.x , indices.y , indices.z , m_chunkLoadingData->remainingChunks .size ());
220+
221+ lock.unlock ();
222+
223+ Chunk* chunk = GetPlanet ().GetChunk (indices);
224+ if (!chunk)
225+ chunk = &GetPlanet ().AddChunk (m_serverInstance.GetBlockLibrary (), indices);
226+
227+ auto & taskScheduler = m_serverInstance.GetApplication ().GetComponent <Nz::TaskSchedulerAppComponent>();
228+
229+ m_chunkLoadingData->chunkLoadingCount ++;
230+ taskScheduler.AddTask ([chunk, serverInstance = &m_serverInstance, databaseId = m_databaseId, chunkLoadingData = m_chunkLoadingData, seed = m_generationSeed, chunkCount = m_chunkCount, generatorName = m_generatorName]
231+ {
232+ bool chunkFound = false ;
233+ if (databaseId)
234+ {
235+ ServerDatabase& serverDatabase = serverInstance->GetServerDatabase ();
236+ chunkFound = serverDatabase.GetPlanetChunk (*databaseId, chunk->GetIndices (), [&](Database::PlanetChunk&& planetChunk)
237+ {
238+ if (planetChunk.version != s_chunkVersion)
239+ throw std::runtime_error (fmt::format (" unhandled version {}" , planetChunk.version ));
240+
241+ // Chunk data has decompressedSize first
242+ Nz::UInt32 decompressedSize;
243+ std::memcpy (&decompressedSize, &planetChunk.chunkData [0 ], sizeof (decompressedSize));
244+ decompressedSize = Nz::LittleEndianToHost (decompressedSize);
245+
246+ BinaryCompressor& binaryCompressor = BinaryCompressor::GetThreadCompressor ();
247+
248+ std::vector<Nz::UInt8> decompressedData (decompressedSize);
249+ std::optional compressedDataOpt = binaryCompressor.Decompress (planetChunk.chunkData .data () + sizeof (decompressedSize), planetChunk.chunkData .size () - sizeof (decompressedSize), decompressedData.data (), decompressedData.size ());
250+ if (!compressedDataOpt)
251+ throw std::runtime_error (" chunk decompression failed" );
252+
253+ if (*compressedDataOpt != decompressedSize)
254+ throw std::runtime_error (" chunk decompression failed (corrupt size)" );
255+
256+ Nz::ByteStream byteStream (decompressedData.data (), decompressedData.size ());
257+
258+ chunk->LockWrite ();
259+ chunk->Deserialize (byteStream);
260+ chunk->UnlockWrite ();
261+ });
262+ }
263+
264+ if (!chunkFound)
265+ chunkLoadingData->planet ->GenerateChunk (*chunk, seed, chunkCount, generatorName);
266+
267+ chunkLoadingData->HandleChunkLoaded (chunk->GetIndices ());
268+
269+ if (--chunkLoadingData->chunkLoadingCount == 0 && chunkLoadingData->remainingChunks .empty ())
270+ spdlog::debug (" planet chunk loading finished, total chunks: {} (out of {})\n " , chunkLoadingData->visitedChunks .size (), chunkCount.x * chunkCount.y * chunkCount.z );
271+ });
272+ }
273+ }
274+
216275 ServerAtmosphere* ServerPlanetEnvironment::GetFallbackAtmosphereAtPosition (const Nz::Vector3f& position)
217276 {
218277 Planet& planet = GetPlanet ();
@@ -286,4 +345,28 @@ namespace tsom
286345 return true ;
287346 });
288347 }
348+
349+ void ServerPlanetEnvironment::ChunkLoadingData::HandleChunkLoaded (const ChunkIndices& chunkIndices)
350+ {
351+ ChunkIndices minIndices (-int (chunkCount.x / 2 ), -int (chunkCount.y / 2 ), -int (chunkCount.z / 2 ));
352+ ChunkIndices maxIndices = minIndices + ChunkIndices (chunkCount) - ChunkIndices (1 );
353+
354+ std::unique_lock lock (mutex);
355+
356+ DirectionMask visibilityMask = planet->GetChunkVisibilityMask (chunkIndices);
357+ for (Direction visibleNeighborDir : visibilityMask)
358+ {
359+ ChunkIndices neighborIndices = chunkIndices + s_chunkDirOffset[visibleNeighborDir];
360+ if (neighborIndices.x < minIndices.x || neighborIndices.x > maxIndices.x ||
361+ neighborIndices.y < minIndices.y || neighborIndices.y > maxIndices.y ||
362+ neighborIndices.z < minIndices.z || neighborIndices.z > maxIndices.z )
363+ continue ;
364+
365+ if (visitedChunks.contains (neighborIndices))
366+ continue ;
367+
368+ visitedChunks.insert (neighborIndices);
369+ remainingChunks.push (neighborIndices);
370+ }
371+ }
289372}
0 commit comments