diff --git a/doc/classes/TileMapLayer.xml b/doc/classes/TileMapLayer.xml index 6cbec9c2aaa..e814d76b73e 100644 --- a/doc/classes/TileMapLayer.xml +++ b/doc/classes/TileMapLayer.xml @@ -22,6 +22,21 @@ [b]Note:[/b] If the properties of [param tile_data] object should change over time, use [method notify_runtime_tile_data_update] to notify the [TileMapLayer] it needs an update. + + + + + + Called when this [TileMapLayer]'s cells need an internal update. This update may be caused from individual cells being modified or by a change in the [member tile_set] (causing all cells to be queued for an update). The first call to this function is always for initializing all the [TileMapLayer]'s cells. [param coords] contains the coordinates of all modified cells, roughly in the order they were modified. [param forced_cleanup] is [code]true[/code] when the [TileMapLayer]'s internals should be fully cleaned up. This is the case when: + - The layer is disabled; + - The layer is not visible; + - [member tile_set] is set to [code]null[/code]; + - The node is removed from the tree; + - The node is freed. + Note that any internal update happening while one of these conditions is verified is considered to be a "cleanup". See also [method update_internals]. + [b]Warning:[/b] Implementing this method may degrade the [TileMapLayer]'s performance. + + diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp index 30bd59c1a26..c4a2f35d318 100644 --- a/scene/2d/tile_map_layer.cpp +++ b/scene/2d/tile_map_layer.cpp @@ -1460,6 +1460,24 @@ void TileMapLayer::_clear_runtime_update_tile_data_for_cell(CellData &r_cell_dat } } +void TileMapLayer::_update_cells_callback(bool p_force_cleanup) { + if (!GDVIRTUAL_IS_OVERRIDDEN(_update_cells)) { + return; + } + + // Check if we should cleanup everything. + bool forced_cleanup = p_force_cleanup || !enabled || tile_set.is_null() || !is_visible_in_tree(); + + // List all the dirty cell's positions to notify script of cell updates. + TypedArray dirty_cell_positions; + for (SelfList *cell_data_list_element = dirty.cell_list.first(); cell_data_list_element; cell_data_list_element = cell_data_list_element->next()) { + CellData &cell_data = *cell_data_list_element->self(); + dirty_cell_positions.push_back(cell_data.coords); + } + + GDVIRTUAL_CALL(_update_cells, dirty_cell_positions, forced_cleanup); +} + TileSet::TerrainsPattern TileMapLayer::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet &p_constraints, TileSet::TerrainsPattern p_current_pattern) const { if (tile_set.is_null()) { return TileSet::TerrainsPattern(); @@ -1673,6 +1691,10 @@ void TileMapLayer::_internal_update(bool p_force_cleanup) { // This may add cells to the dirty list if a runtime modification has been notified. _build_runtime_update_tile_data(p_force_cleanup); + // Callback for implementing custom subsystems. + // This may add to the dirty list if some cells are changed inside _update_cells. + _update_cells_callback(p_force_cleanup); + // Update all subsystems. _rendering_update(p_force_cleanup); _physics_update(p_force_cleanup); @@ -1861,6 +1883,7 @@ void TileMapLayer::_bind_methods() { GDVIRTUAL_BIND(_use_tile_data_runtime_update, "coords"); GDVIRTUAL_BIND(_tile_data_runtime_update, "coords", "tile_data"); + GDVIRTUAL_BIND(_update_cells, "coords", "forced_cleanup"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "tile_map_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_tile_map_data_from_array", "get_tile_map_data_as_array"); diff --git a/scene/2d/tile_map_layer.h b/scene/2d/tile_map_layer.h index 6cb481849c5..912fa2be155 100644 --- a/scene/2d/tile_map_layer.h +++ b/scene/2d/tile_map_layer.h @@ -321,6 +321,7 @@ private: bool _runtime_update_needs_all_cells_cleaned_up = false; void _clear_runtime_update_tile_data(); void _clear_runtime_update_tile_data_for_cell(CellData &r_cell_data); + void _update_cells_callback(bool p_force_cleanup); // Per-system methods. #ifdef DEBUG_ENABLED @@ -462,6 +463,7 @@ public: void notify_runtime_tile_data_update(); GDVIRTUAL1R(bool, _use_tile_data_runtime_update, Vector2i); GDVIRTUAL2(_tile_data_runtime_update, Vector2i, TileData *); + GDVIRTUAL2(_update_cells, TypedArray, bool); // --- Shortcuts to methods defined in TileSet --- Vector2i map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref p_pattern);