diff --git a/world/default/terrain_chunk_default.cpp b/world/default/terrain_chunk_default.cpp index fd6f725..ae65542 100644 --- a/world/default/terrain_chunk_default.cpp +++ b/world/default/terrain_chunk_default.cpp @@ -732,7 +732,10 @@ void TerrainChunkDefault::_visibility_changed(bool visible) { void TerrainChunkDefault::_exit_tree() { TerrainChunk::_exit_tree(); - rids_free(); + if (!_is_generating) { + rids_free(); + rids_clear(); + } } void TerrainChunkDefault::_world_transform_changed() { @@ -874,6 +877,9 @@ TerrainChunkDefault::~TerrainChunkDefault() { _lights.clear(); debug_mesh_free(); + + rids_free(); + rids_clear(); } void TerrainChunkDefault::_channel_setup() { diff --git a/world/terrain_chunk.cpp b/world/terrain_chunk.cpp index 84f0877..81d27c8 100644 --- a/world/terrain_chunk.cpp +++ b/world/terrain_chunk.cpp @@ -28,6 +28,7 @@ SOFTWARE. #include "../defines.h" +#include "core/message_queue.h" #include "jobs/terrain_job.h" #include "terrain_structure.h" @@ -65,6 +66,10 @@ _FORCE_INLINE_ void TerrainChunk::set_is_generating(const bool value) { _is_generating = value; } +bool TerrainChunk::is_build_aborted() const { + return _abort_build; +} + bool TerrainChunk::is_in_tree() const { return _is_in_tree; } @@ -268,6 +273,12 @@ int TerrainChunk::job_get_current_index() { return _current_job; } void TerrainChunk::job_next() { + if (_abort_build) { + _is_generating = false; + _current_job = -1; + return; + } + _THREAD_SAFE_METHOD_ ++_current_job; @@ -676,6 +687,22 @@ void TerrainChunk::finalize_build() { } } +void TerrainChunk::cancel_build() { + _queued_generation = false; + + _abort_build = true; + +#if THREAD_POOL_PRESENT + if (_is_generating) { + Ref job = job_get_current(); + + if (job.is_valid()) { + ThreadPool::get_singleton()->cancel_job(job); + } + } +#endif +} + void TerrainChunk::bake_lights() { if (has_method("_bake_lights")) call("_bake_lights"); @@ -966,12 +993,6 @@ void TerrainChunk::enter_tree() { void TerrainChunk::exit_tree() { _is_in_tree = false; - if (_library.is_valid() && _library->supports_caching()) { - if (material_cache_key_has()) { - _library->material_cache_unref(material_cache_key_get()); - } - } - if (has_method("_exit_tree")) call("_exit_tree"); } @@ -1026,6 +1047,24 @@ Vector3 TerrainChunk::to_global(Vector3 p_local) const { return get_global_transform().xform(p_local); } +bool TerrainChunk::is_safe_to_delete() { +#if THREAD_POOL_PRESENT + if (!_is_generating) { + return true; + } + + Ref job = job_get_current(); + + if (!job.is_valid()) { + return true; + } + + return !ThreadPool::get_singleton()->has_job(job); +#else + return true; +#endif +} + TerrainChunk::TerrainChunk() { _is_processing = false; _is_phisics_processing = false; @@ -1110,7 +1149,9 @@ void TerrainChunk::_enter_tree() { } void TerrainChunk::_exit_tree() { - _abort_build = true; + if (_is_generating) { + cancel_build(); + } for (int i = 0; i < _jobs.size(); ++i) { Ref j = _jobs[i]; @@ -1119,9 +1160,19 @@ void TerrainChunk::_exit_tree() { j->chunk_exit_tree(); } } + + if (_library.is_valid() && _library->supports_caching()) { + if (material_cache_key_has()) { + _library->material_cache_unref(material_cache_key_get()); + } + } } void TerrainChunk::_generation_process(const float delta) { + if (_abort_build) { + return; + } + _THREAD_SAFE_METHOD_ if (_current_job < 0 || _current_job >= _jobs.size()) @@ -1147,6 +1198,10 @@ void TerrainChunk::_generation_process(const float delta) { } } void TerrainChunk::_generation_physics_process(const float delta) { + if (_abort_build) { + return; + } + _THREAD_SAFE_METHOD_ if (_current_job < 0 || _current_job >= _jobs.size()) @@ -1270,6 +1325,8 @@ void TerrainChunk::_bind_methods() { ClassDB::bind_method(D_METHOD("finalize_build"), &TerrainChunk::finalize_build); + ClassDB::bind_method(D_METHOD("cancel_build"), &TerrainChunk::cancel_build); + ClassDB::bind_method(D_METHOD("get_process"), &TerrainChunk::get_process); ClassDB::bind_method(D_METHOD("set_process", "value"), &TerrainChunk::set_process); @@ -1290,6 +1347,8 @@ void TerrainChunk::_bind_methods() { ClassDB::bind_method(D_METHOD("set_is_generating", "value"), &TerrainChunk::set_is_generating); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_generating", PROPERTY_HINT_NONE, "", 0), "set_is_generating", "get_is_generating"); + ClassDB::bind_method(D_METHOD("is_build_aborted"), &TerrainChunk::is_build_aborted); + ClassDB::bind_method(D_METHOD("get_dirty"), &TerrainChunk::get_dirty); ClassDB::bind_method(D_METHOD("set_dirty", "value"), &TerrainChunk::set_dirty); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dirty", PROPERTY_HINT_NONE, "", 0), "set_dirty", "get_dirty"); @@ -1498,4 +1557,6 @@ void TerrainChunk::_bind_methods() { ClassDB::bind_method(D_METHOD("_generation_process"), &TerrainChunk::_generation_process); ClassDB::bind_method(D_METHOD("_generation_physics_process"), &TerrainChunk::_generation_physics_process); + + ClassDB::bind_method(D_METHOD("is_safe_to_delete"), &TerrainChunk::is_safe_to_delete); } diff --git a/world/terrain_chunk.h b/world/terrain_chunk.h index 4de5cdf..8306563 100644 --- a/world/terrain_chunk.h +++ b/world/terrain_chunk.h @@ -95,6 +95,8 @@ public: bool get_is_generating() const; void set_is_generating(const bool value); + bool is_build_aborted() const; + bool is_in_tree() const; bool get_dirty() const; @@ -222,6 +224,7 @@ public: void build(); void clear(); void finalize_build(); + void cancel_build(); void _build(); @@ -304,6 +307,8 @@ public: Vector3 to_local(Vector3 p_global) const; Vector3 to_global(Vector3 p_local) const; + bool is_safe_to_delete(); + TerrainChunk(); ~TerrainChunk(); diff --git a/world/terrain_world.cpp b/world/terrain_world.cpp index b4dee8c..fc06c4c 100644 --- a/world/terrain_world.cpp +++ b/world/terrain_world.cpp @@ -24,6 +24,7 @@ SOFTWARE. #include "core/version.h" +#include "core/message_queue.h" #include "terrain_chunk.h" #include "terrain_structure.h" @@ -291,11 +292,14 @@ Ref TerrainWorld::chunk_get(const int x, const int z) { Ref TerrainWorld::chunk_remove(const int x, const int z) { IntPos pos(x, z); - if (!_chunks.has(pos)) + if (!_chunks.has(pos)) { return NULL; + } Ref chunk = _chunks.get(pos); + chunk->exit_tree(); + for (int i = 0; i < _chunks_vector.size(); ++i) { if (_chunks_vector.get(i) == chunk) { _chunks_vector.VREMOVE(i); @@ -303,7 +307,14 @@ Ref TerrainWorld::chunk_remove(const int x, const int z) { } } - chunk->exit_tree(); + _generation_queue.erase(chunk); + + if (chunk->get_is_generating()) { + chunk->cancel_build(); + } + + //never remove from this here + //_generating.erase(chunk); _chunks.erase(pos); @@ -315,9 +326,18 @@ Ref TerrainWorld::chunk_remove_index(const int index) { ERR_FAIL_INDEX_V(index, _chunks_vector.size(), NULL); Ref chunk = _chunks_vector.get(index); + chunk->exit_tree(); + _chunks_vector.VREMOVE(index); _chunks.erase(IntPos(chunk->get_position_x(), chunk->get_position_z())); - chunk->exit_tree(); + _generation_queue.erase(chunk); + + if (chunk->get_is_generating()) { + chunk->cancel_build(); + } + + //never remove from this here + //_generating.erase(chunk); emit_signal("chunk_removed", chunk); @@ -343,11 +363,19 @@ void TerrainWorld::chunks_clear() { } _chunks_vector.clear(); - _chunks.clear(); - _generation_queue.clear(); - _generating.clear(); + + for (int i = 0; i < _generating.size(); ++i) { + Ref chunk = _generating[i]; + + if (chunk->get_is_generating()) { + chunk->cancel_build(); + } + } + + //never remove from this here + //_generating.clear(); } Ref TerrainWorld::chunk_get_or_create(int x, int z) { @@ -433,7 +461,16 @@ void TerrainWorld::chunks_set(const Vector &chunks) { if (chunks.find(chunk) == -1) { chunk_remove_index(i); _generation_queue.erase(chunk); - _generating.erase(chunk); + + chunk->exit_tree(); + + if (chunk->get_is_generating()) { + chunk->cancel_build(); + } + + //never remove from this here + //_generating.erase(chunk); + --i; } } @@ -963,7 +1000,19 @@ void TerrainWorld::_notification(int p_what) { for (int i = 0; i < _generating.size(); ++i) { Ref chunk = _generating.get(i); - if (!chunk.is_valid() || !chunk->get_is_generating()) { + if (!chunk.is_valid()) { + _generating.VREMOVE(i); + --i; + continue; + } + + if (!chunk->get_is_generating()) { + _generating.VREMOVE(i); + --i; + continue; + } + + if (chunk->is_build_aborted() && chunk->is_safe_to_delete()) { _generating.VREMOVE(i); --i; continue;