Split data request

master
Marc Gilleron 2022-02-02 23:12:59 +00:00
parent b7e56c6bec
commit c6199563c8
8 changed files with 371 additions and 302 deletions

View File

@ -1,231 +0,0 @@
#include "block_data_request.h"
#include "../util/godot/funcs.h"
#include "../util/macros.h"
#include "../util/profiling.h"
#include "block_generate_request.h"
#include "voxel_server.h"
namespace zylann::voxel {
namespace {
std::atomic_int g_debug_stream_tasks_count;
}
BlockDataRequest::BlockDataRequest(uint32_t p_volume_id, Vector3i p_block_pos, uint8_t p_lod, uint8_t p_block_size,
bool p_request_instances, std::shared_ptr<StreamingDependency> p_stream_dependency,
PriorityDependency p_priority_dependency) :
_volume_id(p_volume_id),
_position(p_block_pos),
_lod(p_lod),
_block_size(p_block_size),
_type(TYPE_LOAD),
_request_voxels(true),
_request_instances(p_request_instances),
_stream_dependency(p_stream_dependency),
_priority_dependency(p_priority_dependency) {
//
++g_debug_stream_tasks_count;
}
BlockDataRequest::BlockDataRequest(uint32_t p_volume_id, Vector3i p_block_pos, uint8_t p_lod, uint8_t p_block_size,
std::shared_ptr<VoxelBufferInternal> p_voxels, std::shared_ptr<StreamingDependency> p_stream_dependency) :
_volume_id(p_volume_id),
_position(p_block_pos),
_lod(p_lod),
_block_size(p_block_size),
_type(TYPE_SAVE),
_request_voxels(true),
_request_instances(false),
_stream_dependency(p_stream_dependency),
_voxels(p_voxels) {
//
++g_debug_stream_tasks_count;
}
// For saving instances
BlockDataRequest::BlockDataRequest(uint32_t p_volume_id, Vector3i p_block_pos, uint8_t p_lod, uint8_t p_block_size,
std::unique_ptr<InstanceBlockData> p_instances, std::shared_ptr<StreamingDependency> p_stream_dependency) :
_volume_id(p_volume_id),
_position(p_block_pos),
_lod(p_lod),
_block_size(p_block_size),
_type(TYPE_SAVE),
_request_voxels(false),
_request_instances(true),
_stream_dependency(p_stream_dependency),
_instances(std::move(p_instances)) {
//
++g_debug_stream_tasks_count;
}
BlockDataRequest::~BlockDataRequest() {
--g_debug_stream_tasks_count;
}
int BlockDataRequest::debug_get_running_count() {
return g_debug_stream_tasks_count;
}
void BlockDataRequest::run(zylann::ThreadedTaskContext ctx) {
VOXEL_PROFILE_SCOPE();
CRASH_COND(_stream_dependency == nullptr);
Ref<VoxelStream> stream = _stream_dependency->stream;
CRASH_COND(stream.is_null());
const Vector3i origin_in_voxels = (_position << _lod) * _block_size;
switch (_type) {
case TYPE_LOAD: {
ERR_FAIL_COND(_voxels != nullptr);
_voxels = gd_make_shared<VoxelBufferInternal>();
_voxels->create(_block_size, _block_size, _block_size);
// TODO We should consider batching this again, but it needs to be done carefully.
// Each task is one block, and priority depends on distance to closest viewer.
// If we batch blocks, we have to do it by distance too.
// TODO Assign max_lod_hint when available
const VoxelStream::Result voxel_result = stream->load_voxel_block(*_voxels, origin_in_voxels, _lod);
if (voxel_result == VoxelStream::RESULT_ERROR) {
ERR_PRINT("Error loading voxel block");
} else if (voxel_result == VoxelStream::RESULT_BLOCK_NOT_FOUND) {
Ref<VoxelGenerator> generator = _stream_dependency->generator;
if (generator.is_valid()) {
BlockGenerateRequest *r = memnew(BlockGenerateRequest);
r->voxels = _voxels;
r->volume_id = _volume_id;
r->position = _position;
r->lod = _lod;
r->block_size = _block_size;
r->stream_dependency = _stream_dependency;
r->priority_dependency = _priority_dependency;
VoxelServer::get_singleton()->push_async_task(r);
_type = TYPE_FALLBACK_ON_GENERATOR;
} else {
// If there is no generator... what do we do? What defines the format of that empty block?
// If the user leaves the defaults it's fine, but otherwise blocks of inconsistent format can
// end up in the volume and that can cause errors.
// TODO Define format on volume?
}
}
if (_request_instances && stream->supports_instance_blocks()) {
ERR_FAIL_COND(_instances != nullptr);
VoxelStreamInstanceDataRequest instance_data_request;
instance_data_request.lod = _lod;
instance_data_request.position = _position;
VoxelStream::Result instances_result;
stream->load_instance_blocks(Span<VoxelStreamInstanceDataRequest>(&instance_data_request, 1),
Span<VoxelStream::Result>(&instances_result, 1));
if (instances_result == VoxelStream::RESULT_ERROR) {
ERR_PRINT("Error loading instance block");
} else if (voxel_result == VoxelStream::RESULT_BLOCK_FOUND) {
_instances = std::move(instance_data_request.data);
}
// If not found, instances will return null,
// which means it can be generated by the instancer after the meshing process
}
} break;
case TYPE_SAVE: {
if (_request_voxels) {
ERR_FAIL_COND(_voxels == nullptr);
VoxelBufferInternal voxels_copy;
{
RWLockRead lock(_voxels->get_lock());
// TODO Optimization: is that copy necessary? It's possible it was already done while issuing the
// request
_voxels->duplicate_to(voxels_copy, true);
}
_voxels = nullptr;
stream->save_voxel_block(voxels_copy, origin_in_voxels, _lod);
}
if (_request_instances && stream->supports_instance_blocks()) {
// If the provided data is null, it means this instance block was never modified.
// Since we are in a save request, the saved data will revert to unmodified.
// On the other hand, if we want to represent the fact that "everything was deleted here",
// this should not be null.
PRINT_VERBOSE(String("Saving instance block {0} lod {1} with data {2}")
.format(varray(_position, _lod, ptr2s(_instances.get()))));
VoxelStreamInstanceDataRequest instance_data_request;
instance_data_request.lod = _lod;
instance_data_request.position = _position;
instance_data_request.data = std::move(_instances);
stream->save_instance_blocks(Span<VoxelStreamInstanceDataRequest>(&instance_data_request, 1));
}
} break;
default:
CRASH_NOW_MSG("Invalid type");
}
_has_run = true;
}
int BlockDataRequest::get_priority() {
if (_type == TYPE_SAVE) {
return 0;
}
float closest_viewer_distance_sq;
const int p = _priority_dependency.evaluate(_lod, &closest_viewer_distance_sq);
_too_far = closest_viewer_distance_sq > _priority_dependency.drop_distance_squared;
return p;
}
bool BlockDataRequest::is_cancelled() {
return _type == TYPE_LOAD && (!_stream_dependency->valid || _too_far);
}
void BlockDataRequest::apply_result() {
if (VoxelServer::get_singleton()->is_volume_valid(_volume_id)) {
// TODO Comparing pointer may not be guaranteed
// The request response must match the dependency it would have been requested with.
// If it doesn't match, we are no longer interested in the result.
if (_stream_dependency->valid && _type != BlockDataRequest::TYPE_FALLBACK_ON_GENERATOR) {
VoxelServer::BlockDataOutput o;
o.voxels = _voxels;
o.instances = std::move(_instances);
o.position = _position;
o.lod = _lod;
o.dropped = !_has_run;
o.max_lod_hint = _max_lod_hint;
o.initial_load = false;
switch (_type) {
case BlockDataRequest::TYPE_SAVE:
o.type = VoxelServer::BlockDataOutput::TYPE_SAVED;
break;
case BlockDataRequest::TYPE_LOAD:
o.type = VoxelServer::BlockDataOutput::TYPE_LOADED;
break;
default:
CRASH_NOW_MSG("Unexpected data request response type");
}
VoxelServer::VolumeCallbacks callbacks = VoxelServer::get_singleton()->get_volume_callbacks(_volume_id);
CRASH_COND(callbacks.data_output_callback == nullptr);
callbacks.data_output_callback(callbacks.data, o);
}
} else {
// This can happen if the user removes the volume while requests are still about to return
PRINT_VERBOSE("Stream data request response came back but volume wasn't found");
}
}
} // namespace zylann::voxel

View File

@ -1,61 +0,0 @@
#ifndef BLOCK_DATA_REQUEST_H
#define BLOCK_DATA_REQUEST_H
#include "../util/tasks/threaded_task.h"
#include "priority_dependency.h"
#include "streaming_dependency.h"
namespace zylann::voxel {
class BlockDataRequest : public IThreadedTask {
public:
enum Type { //
TYPE_LOAD = 0,
TYPE_SAVE,
TYPE_FALLBACK_ON_GENERATOR
};
// For loading.
// Only this one needs priority, since we want loading to have low latency.
BlockDataRequest(uint32_t p_volume_id, Vector3i p_block_pos, uint8_t p_lod, uint8_t p_block_size,
bool p_request_instances, std::shared_ptr<StreamingDependency> p_stream_dependency,
PriorityDependency p_priority_dependency);
// For saving voxels
BlockDataRequest(uint32_t p_volume_id, Vector3i p_block_pos, uint8_t p_lod, uint8_t p_block_size,
std::shared_ptr<VoxelBufferInternal> p_voxels, std::shared_ptr<StreamingDependency> p_stream_dependency);
// For saving instances
BlockDataRequest(uint32_t p_volume_id, Vector3i p_block_pos, uint8_t p_lod, uint8_t p_block_size,
std::unique_ptr<InstanceBlockData> p_instances, std::shared_ptr<StreamingDependency> p_stream_dependency);
~BlockDataRequest();
void run(ThreadedTaskContext ctx) override;
int get_priority() override;
bool is_cancelled() override;
void apply_result() override;
static int debug_get_running_count();
private:
PriorityDependency _priority_dependency;
std::shared_ptr<VoxelBufferInternal> _voxels;
std::unique_ptr<InstanceBlockData> _instances;
Vector3i _position; // In data blocks of the specified lod
uint32_t _volume_id;
uint8_t _lod;
uint8_t _block_size;
uint8_t _type;
bool _has_run = false;
bool _too_far = false;
bool _request_instances = false;
bool _request_voxels = false;
bool _max_lod_hint = false;
std::shared_ptr<StreamingDependency> _stream_dependency;
// TODO Find a way to separate save, it doesnt need sorting
};
} // namespace zylann::voxel
#endif // BLOCK_DATA_REQUEST_H

View File

@ -2,7 +2,7 @@
#include "../util/godot/funcs.h"
#include "../util/macros.h"
#include "../util/profiling.h"
#include "block_data_request.h"
#include "save_block_data_request.h"
#include "voxel_server.h"
namespace zylann::voxel {
@ -57,8 +57,8 @@ void BlockGenerateRequest::run(zylann::ThreadedTaskContext ctx) {
// No instances, generators are not designed to produce them at this stage yet.
// No priority data, saving doesnt need sorting
BlockDataRequest *r =
memnew(BlockDataRequest(volume_id, position, lod, block_size, voxels_copy, stream_dependency));
SaveBlockDataRequest *r =
memnew(SaveBlockDataRequest(volume_id, position, lod, block_size, voxels_copy, stream_dependency));
VoxelServer::get_singleton()->push_async_task(r);
}

View File

@ -0,0 +1,146 @@
#include "load_block_data_request.h"
#include "../util/godot/funcs.h"
#include "../util/macros.h"
#include "../util/profiling.h"
#include "block_generate_request.h"
#include "voxel_server.h"
namespace zylann::voxel {
namespace {
std::atomic_int g_debug_load_block_tasks_count;
}
LoadBlockDataRequest::LoadBlockDataRequest(uint32_t p_volume_id, Vector3i p_block_pos, uint8_t p_lod,
uint8_t p_block_size, bool p_request_instances, std::shared_ptr<StreamingDependency> p_stream_dependency,
PriorityDependency p_priority_dependency) :
_volume_id(p_volume_id),
_position(p_block_pos),
_lod(p_lod),
_block_size(p_block_size),
_request_voxels(true),
_request_instances(p_request_instances),
_stream_dependency(p_stream_dependency),
_priority_dependency(p_priority_dependency) {
//
++g_debug_load_block_tasks_count;
}
LoadBlockDataRequest::~LoadBlockDataRequest() {
--g_debug_load_block_tasks_count;
}
int LoadBlockDataRequest::debug_get_running_count() {
return g_debug_load_block_tasks_count;
}
void LoadBlockDataRequest::run(zylann::ThreadedTaskContext ctx) {
VOXEL_PROFILE_SCOPE();
CRASH_COND(_stream_dependency == nullptr);
Ref<VoxelStream> stream = _stream_dependency->stream;
CRASH_COND(stream.is_null());
const Vector3i origin_in_voxels = (_position << _lod) * _block_size;
ERR_FAIL_COND(_voxels != nullptr);
_voxels = gd_make_shared<VoxelBufferInternal>();
_voxels->create(_block_size, _block_size, _block_size);
// TODO We should consider batching this again, but it needs to be done carefully.
// Each task is one block, and priority depends on distance to closest viewer.
// If we batch blocks, we have to do it by distance too.
// TODO Assign max_lod_hint when available
const VoxelStream::Result voxel_result = stream->load_voxel_block(*_voxels, origin_in_voxels, _lod);
if (voxel_result == VoxelStream::RESULT_ERROR) {
ERR_PRINT("Error loading voxel block");
} else if (voxel_result == VoxelStream::RESULT_BLOCK_NOT_FOUND) {
Ref<VoxelGenerator> generator = _stream_dependency->generator;
if (generator.is_valid()) {
BlockGenerateRequest *r = memnew(BlockGenerateRequest);
r->voxels = _voxels;
r->volume_id = _volume_id;
r->position = _position;
r->lod = _lod;
r->block_size = _block_size;
r->stream_dependency = _stream_dependency;
r->priority_dependency = _priority_dependency;
VoxelServer::get_singleton()->push_async_task(r);
_fallback_on_generator = true;
} else {
// If there is no generator... what do we do? What defines the format of that empty block?
// If the user leaves the defaults it's fine, but otherwise blocks of inconsistent format can
// end up in the volume and that can cause errors.
// TODO Define format on volume?
}
}
if (_request_instances && stream->supports_instance_blocks()) {
ERR_FAIL_COND(_instances != nullptr);
VoxelStreamInstanceDataRequest instance_data_request;
instance_data_request.lod = _lod;
instance_data_request.position = _position;
VoxelStream::Result instances_result;
stream->load_instance_blocks(Span<VoxelStreamInstanceDataRequest>(&instance_data_request, 1),
Span<VoxelStream::Result>(&instances_result, 1));
if (instances_result == VoxelStream::RESULT_ERROR) {
ERR_PRINT("Error loading instance block");
} else if (voxel_result == VoxelStream::RESULT_BLOCK_FOUND) {
_instances = std::move(instance_data_request.data);
}
// If not found, instances will return null,
// which means it can be generated by the instancer after the meshing process
}
_has_run = true;
}
int LoadBlockDataRequest::get_priority() {
float closest_viewer_distance_sq;
const int p = _priority_dependency.evaluate(_lod, &closest_viewer_distance_sq);
_too_far = closest_viewer_distance_sq > _priority_dependency.drop_distance_squared;
return p;
}
bool LoadBlockDataRequest::is_cancelled() {
return !_stream_dependency->valid || _too_far;
}
void LoadBlockDataRequest::apply_result() {
if (VoxelServer::get_singleton()->is_volume_valid(_volume_id)) {
// TODO Comparing pointer may not be guaranteed
// The request response must match the dependency it would have been requested with.
// If it doesn't match, we are no longer interested in the result.
if (_stream_dependency->valid && !_fallback_on_generator) {
VoxelServer::BlockDataOutput o;
o.voxels = _voxels;
o.instances = std::move(_instances);
o.position = _position;
o.lod = _lod;
o.dropped = !_has_run;
o.max_lod_hint = _max_lod_hint;
o.initial_load = false;
o.type = VoxelServer::BlockDataOutput::TYPE_LOADED;
VoxelServer::VolumeCallbacks callbacks = VoxelServer::get_singleton()->get_volume_callbacks(_volume_id);
CRASH_COND(callbacks.data_output_callback == nullptr);
callbacks.data_output_callback(callbacks.data, o);
}
} else {
// This can happen if the user removes the volume while requests are still about to return
PRINT_VERBOSE("Stream data request response came back but volume wasn't found");
}
}
} // namespace zylann::voxel

View File

@ -0,0 +1,44 @@
#ifndef LOAD_BLOCK_DATA_REQUEST_H
#define LOAD_BLOCK_DATA_REQUEST_H
#include "../util/tasks/threaded_task.h"
#include "priority_dependency.h"
#include "streaming_dependency.h"
namespace zylann::voxel {
class LoadBlockDataRequest : public IThreadedTask {
public:
LoadBlockDataRequest(uint32_t p_volume_id, Vector3i p_block_pos, uint8_t p_lod, uint8_t p_block_size,
bool p_request_instances, std::shared_ptr<StreamingDependency> p_stream_dependency,
PriorityDependency p_priority_dependency);
~LoadBlockDataRequest();
void run(ThreadedTaskContext ctx) override;
int get_priority() override;
bool is_cancelled() override;
void apply_result() override;
static int debug_get_running_count();
private:
PriorityDependency _priority_dependency;
std::shared_ptr<VoxelBufferInternal> _voxels;
std::unique_ptr<InstanceBlockData> _instances;
Vector3i _position; // In data blocks of the specified lod
uint32_t _volume_id;
uint8_t _lod;
uint8_t _block_size;
bool _has_run = false;
bool _too_far = false;
bool _request_instances = false;
bool _request_voxels = false;
bool _max_lod_hint = false;
bool _fallback_on_generator = false;
std::shared_ptr<StreamingDependency> _stream_dependency;
};
} // namespace zylann::voxel
#endif // LOAD_BLOCK_DATA_REQUEST_H

View File

@ -0,0 +1,125 @@
#include "save_block_data_request.h"
#include "../util/godot/funcs.h"
#include "../util/macros.h"
#include "../util/profiling.h"
#include "block_generate_request.h"
#include "voxel_server.h"
namespace zylann::voxel {
namespace {
std::atomic_int g_debug_save_block_tasks_count;
}
SaveBlockDataRequest::SaveBlockDataRequest(uint32_t p_volume_id, Vector3i p_block_pos, uint8_t p_lod,
uint8_t p_block_size, std::shared_ptr<VoxelBufferInternal> p_voxels,
std::shared_ptr<StreamingDependency> p_stream_dependency) :
_volume_id(p_volume_id),
_position(p_block_pos),
_lod(p_lod),
_block_size(p_block_size),
_save_voxels(true),
_save_instances(false),
_stream_dependency(p_stream_dependency),
_voxels(p_voxels) {
//
++g_debug_save_block_tasks_count;
}
SaveBlockDataRequest::SaveBlockDataRequest(uint32_t p_volume_id, Vector3i p_block_pos, uint8_t p_lod,
uint8_t p_block_size, std::unique_ptr<InstanceBlockData> p_instances,
std::shared_ptr<StreamingDependency> p_stream_dependency) :
_volume_id(p_volume_id),
_position(p_block_pos),
_lod(p_lod),
_block_size(p_block_size),
_save_voxels(false),
_save_instances(true),
_stream_dependency(p_stream_dependency),
_instances(std::move(p_instances)) {
//
++g_debug_save_block_tasks_count;
}
SaveBlockDataRequest::~SaveBlockDataRequest() {
--g_debug_save_block_tasks_count;
}
int SaveBlockDataRequest::debug_get_running_count() {
return g_debug_save_block_tasks_count;
}
void SaveBlockDataRequest::run(zylann::ThreadedTaskContext ctx) {
VOXEL_PROFILE_SCOPE();
CRASH_COND(_stream_dependency == nullptr);
Ref<VoxelStream> stream = _stream_dependency->stream;
CRASH_COND(stream.is_null());
const Vector3i origin_in_voxels = (_position << _lod) * _block_size;
if (_save_voxels) {
ERR_FAIL_COND(_voxels == nullptr);
VoxelBufferInternal voxels_copy;
{
RWLockRead lock(_voxels->get_lock());
// TODO Optimization: is that copy necessary? It's possible it was already done while issuing the
// request
_voxels->duplicate_to(voxels_copy, true);
}
_voxels = nullptr;
stream->save_voxel_block(voxels_copy, origin_in_voxels, _lod);
}
if (_save_instances && stream->supports_instance_blocks()) {
// If the provided data is null, it means this instance block was never modified.
// Since we are in a save request, the saved data will revert to unmodified.
// On the other hand, if we want to represent the fact that "everything was deleted here",
// this should not be null.
PRINT_VERBOSE(String("Saving instance block {0} lod {1} with data {2}")
.format(varray(_position, _lod, ptr2s(_instances.get()))));
VoxelStreamInstanceDataRequest instance_data_request;
instance_data_request.lod = _lod;
instance_data_request.position = _position;
instance_data_request.data = std::move(_instances);
stream->save_instance_blocks(Span<VoxelStreamInstanceDataRequest>(&instance_data_request, 1));
}
_has_run = true;
}
int SaveBlockDataRequest::get_priority() {
return 0;
}
bool SaveBlockDataRequest::is_cancelled() {
return false;
}
void SaveBlockDataRequest::apply_result() {
if (VoxelServer::get_singleton()->is_volume_valid(_volume_id)) {
if (_stream_dependency->valid) {
VoxelServer::BlockDataOutput o;
o.voxels = _voxels;
o.instances = std::move(_instances);
o.position = _position;
o.lod = _lod;
o.dropped = !_has_run;
o.max_lod_hint = false; // Unused
o.initial_load = false; // Unused
o.type = VoxelServer::BlockDataOutput::TYPE_SAVED;
VoxelServer::VolumeCallbacks callbacks = VoxelServer::get_singleton()->get_volume_callbacks(_volume_id);
CRASH_COND(callbacks.data_output_callback == nullptr);
callbacks.data_output_callback(callbacks.data, o);
}
} else {
// This can happen if the user removes the volume while requests are still about to return
PRINT_VERBOSE("Stream data request response came back but volume wasn't found");
}
}
} // namespace zylann::voxel

View File

@ -0,0 +1,43 @@
#ifndef SAVE_BLOCK_DATA_REQUEST_H
#define SAVE_BLOCK_DATA_REQUEST_H
#include "../util/tasks/threaded_task.h"
#include "streaming_dependency.h"
namespace zylann::voxel {
class SaveBlockDataRequest : public IThreadedTask {
public:
// For saving voxels only
SaveBlockDataRequest(uint32_t p_volume_id, Vector3i p_block_pos, uint8_t p_lod, uint8_t p_block_size,
std::shared_ptr<VoxelBufferInternal> p_voxels, std::shared_ptr<StreamingDependency> p_stream_dependency);
// For saving instances only
SaveBlockDataRequest(uint32_t p_volume_id, Vector3i p_block_pos, uint8_t p_lod, uint8_t p_block_size,
std::unique_ptr<InstanceBlockData> p_instances, std::shared_ptr<StreamingDependency> p_stream_dependency);
~SaveBlockDataRequest();
void run(ThreadedTaskContext ctx) override;
int get_priority() override;
bool is_cancelled() override;
void apply_result() override;
static int debug_get_running_count();
private:
std::shared_ptr<VoxelBufferInternal> _voxels;
std::unique_ptr<InstanceBlockData> _instances;
Vector3i _position; // In data blocks of the specified lod
uint32_t _volume_id;
uint8_t _lod;
uint8_t _block_size;
bool _has_run = false;
bool _save_instances = false;
bool _save_voxels = false;
std::shared_ptr<StreamingDependency> _stream_dependency;
};
} // namespace zylann::voxel
#endif // SAVE_BLOCK_DATA_REQUEST_H

View File

@ -6,8 +6,9 @@
#include "../util/macros.h"
#include "../util/profiling.h"
#include "all_blocks_data_request.h"
#include "block_data_request.h"
#include "block_generate_request.h"
#include "load_block_data_request.h"
#include "save_block_data_request.h"
#include <core/config/project_settings.h>
#include <core/os/memory.h>
@ -100,7 +101,8 @@ VoxelServer::VoxelServer() {
// Init world
_world.shared_priority_dependency = gd_make_shared<PriorityDependency::ViewersData>();
PRINT_VERBOSE(String("Size of BlockDataRequest: {0}").format(varray((int)sizeof(BlockDataRequest))));
PRINT_VERBOSE(String("Size of LoadBlockDataRequest: {0}").format(varray((int)sizeof(LoadBlockDataRequest))));
PRINT_VERBOSE(String("Size of SaveBlockDataRequest: {0}").format(varray((int)sizeof(SaveBlockDataRequest))));
PRINT_VERBOSE(String("Size of BlockMeshRequest: {0}").format(varray((int)sizeof(BlockMeshRequest))));
}
@ -294,7 +296,7 @@ void VoxelServer::request_block_load(uint32_t volume_id, Vector3i block_pos, int
PriorityDependency priority_dependency;
init_priority_dependency(priority_dependency, block_pos, lod, volume, volume.data_block_size);
BlockDataRequest *r = memnew(BlockDataRequest(volume_id, block_pos, lod, volume.data_block_size,
LoadBlockDataRequest *r = memnew(LoadBlockDataRequest(volume_id, block_pos, lod, volume.data_block_size,
request_instances, volume.stream_dependency, priority_dependency));
_streaming_thread_pool.enqueue(r);
@ -356,8 +358,8 @@ void VoxelServer::request_voxel_block_save(
ERR_FAIL_COND(volume.stream.is_null());
CRASH_COND(volume.stream_dependency == nullptr);
BlockDataRequest *r = memnew(
BlockDataRequest(volume_id, block_pos, lod, volume.data_block_size, voxels, volume.stream_dependency));
SaveBlockDataRequest *r = memnew(
SaveBlockDataRequest(volume_id, block_pos, lod, volume.data_block_size, voxels, volume.stream_dependency));
// No priority data, saving doesnt need sorting
@ -370,7 +372,7 @@ void VoxelServer::request_instance_block_save(
ERR_FAIL_COND(volume.stream.is_null());
CRASH_COND(volume.stream_dependency == nullptr);
BlockDataRequest *r = memnew(BlockDataRequest(
SaveBlockDataRequest *r = memnew(SaveBlockDataRequest(
volume_id, block_pos, lod, volume.data_block_size, std::move(instances), volume.stream_dependency));
// No priority data, saving doesnt need sorting
@ -587,7 +589,8 @@ VoxelServer::Stats VoxelServer::get_stats() const {
s.general = debug_get_pool_stats(_general_thread_pool);
s.generation_tasks = BlockGenerateRequest::debug_get_running_count();
s.meshing_tasks = BlockMeshRequest::debug_get_running_count();
s.streaming_tasks = BlockDataRequest::debug_get_running_count();
s.streaming_tasks =
LoadBlockDataRequest::debug_get_running_count() + SaveBlockDataRequest::debug_get_running_count();
s.main_thread_tasks = _time_spread_task_runner.get_pending_count() + _progressive_task_runner.get_pending_count();
return s;
}