diff --git a/core/src/ChunkPipeline.cpp b/core/src/ChunkPipeline.cpp index 067eec5..ab27136 100644 --- a/core/src/ChunkPipeline.cpp +++ b/core/src/ChunkPipeline.cpp @@ -317,3 +317,105 @@ void ChunkPipeline::run() { completedResults.push_back(std::move(slot)); } + for (const Vec3i& coord : chunkStore.residentCoords()) { + if (inViewVolume(coord)) chunkStore.pin(coord); + else chunkStore.unpin(coord); + } + + std::lock_guard lock(controlMutex); + for (int stage = 0; stage < chunkStageCount; ++stage) { + std::size_t at = static_cast(stage); + counters.stageCompleted[at] += delta.stageCompleted[at]; + counters.stageNanos[at] += delta.stageNanos[at]; + } + counters.cancelled += delta.cancelled; + counters.chunksReady += delta.chunksReady; + counters.cachedBytes = chunkStore.bytesUsed(); + pending.clear(); + pendingSet.clear(); + activeIndex.clear(); + cancelFlags.clear(); +} + +const ChunkTaskResult* ChunkPipeline::resultFor(const Vec3i& chunkCoord) const { + auto found = resultIndex.find(chunkCoord); + if (found == resultIndex.end()) return nullptr; + return &completedResults[found->second]; +} + +PipelineStats ChunkPipeline::stats() const { + std::lock_guard lock(controlMutex); + return counters; +} + +void ChunkPipeline::resetStats() { + std::lock_guard lock(controlMutex); + counters = PipelineStats{}; +} + +std::vector ChunkPipeline::digest() const { + std::vector bytes; + auto appendRaw = [&bytes](const void* source, std::size_t size) { + const std::uint8_t* first = static_cast(source); + bytes.insert(bytes.end(), first, first + size); + }; + auto appendInt = [&appendRaw](int value) { + std::int32_t narrowed = value; + appendRaw(&narrowed, sizeof(narrowed)); + }; + auto appendCount = [&appendRaw](std::uint64_t value) { appendRaw(&value, sizeof(value)); }; + auto appendMesh = [&](const Mesh& mesh) { + appendCount(mesh.vertices.size()); + if (!mesh.vertices.empty()) + appendRaw(mesh.vertices.data(), mesh.vertices.size() * sizeof(Vertex)); + appendCount(mesh.indices.size()); + if (!mesh.indices.empty()) + appendRaw(mesh.indices.data(), mesh.indices.size() * sizeof(std::uint32_t)); + }; + + std::vector worldCoords; + worldCoords.reserve(world.chunkCount()); + for (const auto& slot : world.allChunks()) worldCoords.push_back(slot.first); + std::sort(worldCoords.begin(), worldCoords.end(), coordLess); + + appendCount(worldCoords.size()); + for (const Vec3i& coord : worldCoords) { + appendInt(coord.x); + appendInt(coord.y); + appendInt(coord.z); + const Chunk* chunk = world.chunkAt(coord); + appendRaw(chunk->raw().data(), chunk->raw().size() * sizeof(Block)); + } + + appendCount(completedResults.size()); + for (const ChunkTaskResult& produced : completedResults) { + appendInt(produced.coord.x); + appendInt(produced.coord.y); + appendInt(produced.coord.z); + bytes.push_back(static_cast(produced.stage)); + bytes.push_back(produced.cancelled ? 1u : 0u); + appendRaw(produced.chunk.raw().data(), produced.chunk.raw().size() * sizeof(Block)); + appendCount(produced.light.sun.size()); + if (!produced.light.sun.empty()) + appendRaw(produced.light.sun.data(), produced.light.sun.size()); + if (!produced.light.block.empty()) + appendRaw(produced.light.block.data(), produced.light.block.size()); + appendMesh(produced.mesh.opaque); + appendMesh(produced.mesh.transparent); + appendCount(produced.entryBytes); + } + + std::vector cached = chunkStore.residentCoords(); + appendCount(cached.size()); + appendCount(chunkStore.bytesUsed()); + for (const Vec3i& coord : cached) { + appendInt(coord.x); + appendInt(coord.y); + appendInt(coord.z); + bytes.push_back(chunkStore.hasMesh(coord) ? 1u : 0u); + bytes.push_back(chunkStore.isPinned(coord) ? 1u : 0u); + } + return bytes; +} + +} // namespace vf