Browse Source

Remove almost all remaining dependencies of TileMapLayer on TileMap

Gilles Roudière 1 year ago
parent
commit
787c784aca
5 changed files with 294 additions and 182 deletions
  1. 22 38
      scene/2d/tile_map.cpp
  2. 3 3
      scene/2d/tile_map.h
  3. 221 117
      scene/2d/tile_map_layer.cpp
  4. 44 20
      scene/2d/tile_map_layer.h
  5. 4 4
      scene/2d/tile_map_layer_group.cpp

+ 22 - 38
scene/2d/tile_map.cpp

@@ -105,7 +105,7 @@ void TileMap::set_rendering_quadrant_size(int p_size) {
 
 	rendering_quadrant_size = p_size;
 	for (TileMapLayer *layer : layers) {
-		layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE);
+		layer->set_rendering_quadrant_size(p_size);
 	}
 	_emit_changed();
 }
@@ -214,11 +214,10 @@ void TileMap::add_layer(int p_to_pos) {
 	TileMapLayer *new_layer = memnew(TileMapLayer);
 	layers.insert(p_to_pos, new_layer);
 	add_child(new_layer, false, INTERNAL_MODE_FRONT);
-	new_layer->force_parent_owned();
 	new_layer->set_name(vformat("Layer%d", p_to_pos));
 	move_child(new_layer, p_to_pos);
 	for (uint32_t i = 0; i < layers.size(); i++) {
-		layers[i]->set_layer_index_in_tile_map_node(i);
+		layers[i]->set_as_tile_map_internal_node(i);
 	}
 	new_layer->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileMap::_emit_changed));
 
@@ -239,7 +238,7 @@ void TileMap::move_layer(int p_layer, int p_to_pos) {
 	layers.remove_at(p_to_pos < p_layer ? p_layer + 1 : p_layer);
 	for (uint32_t i = 0; i < layers.size(); i++) {
 		move_child(layers[i], i);
-		layers[i]->set_layer_index_in_tile_map_node(i);
+		layers[i]->set_as_tile_map_internal_node(i);
 	}
 	notify_property_list_changed();
 
@@ -255,7 +254,7 @@ void TileMap::remove_layer(int p_layer) {
 	layers[p_layer]->queue_free();
 	layers.remove_at(p_layer);
 	for (uint32_t i = 0; i < layers.size(); i++) {
-		layers[i]->set_layer_index_in_tile_map_node(i);
+		layers[i]->set_as_tile_map_internal_node(i);
 	}
 	notify_property_list_changed();
 
@@ -350,7 +349,7 @@ void TileMap::set_collision_visibility_mode(TileMap::VisibilityMode p_show_colli
 	}
 	collision_visibility_mode = p_show_collision;
 	for (TileMapLayer *layer : layers) {
-		layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_COLLISION_VISIBILITY_MODE);
+		layer->set_collision_visibility_mode(TileMapLayer::VisibilityMode(p_show_collision));
 	}
 	_emit_changed();
 }
@@ -365,7 +364,7 @@ void TileMap::set_navigation_visibility_mode(TileMap::VisibilityMode p_show_navi
 	}
 	navigation_visibility_mode = p_show_navigation;
 	for (TileMapLayer *layer : layers) {
-		layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_NAVIGATION_VISIBILITY_MODE);
+		layer->set_navigation_visibility_mode(TileMapLayer::VisibilityMode(p_show_navigation));
 	}
 	_emit_changed();
 }
@@ -380,7 +379,7 @@ void TileMap::set_y_sort_enabled(bool p_enable) {
 	}
 	Node2D::set_y_sort_enabled(p_enable);
 	for (TileMapLayer *layer : layers) {
-		layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED);
+		layer->set_y_sort_enabled(p_enable);
 	}
 	_emit_changed();
 	update_configuration_warnings();
@@ -497,10 +496,10 @@ void TileMap::update_internals() {
 
 void TileMap::notify_runtime_tile_data_update(int p_layer) {
 	if (p_layer >= 0) {
-		TILEMAP_CALL_FOR_LAYER(p_layer, notify_tile_map_change, TileMapLayer::DIRTY_FLAGS_TILE_MAP_RUNTIME_UPDATE);
+		TILEMAP_CALL_FOR_LAYER(p_layer, notify_runtime_tile_data_update);
 	} else {
 		for (TileMapLayer *layer : layers) {
-			layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_RUNTIME_UPDATE);
+			layer->notify_runtime_tile_data_update();
 		}
 	}
 }
@@ -539,9 +538,8 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
 			if (layers.size() == 0) {
 				TileMapLayer *new_layer = memnew(TileMapLayer);
 				add_child(new_layer, false, INTERNAL_MODE_FRONT);
-				new_layer->force_parent_owned();
+				new_layer->set_as_tile_map_internal_node(0);
 				new_layer->set_name("Layer0");
-				new_layer->set_layer_index_in_tile_map_node(0);
 				new_layer->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileMap::_emit_changed));
 				layers.push_back(new_layer);
 			}
@@ -565,9 +563,8 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
 			while (index >= (int)layers.size()) {
 				TileMapLayer *new_layer = memnew(TileMapLayer);
 				add_child(new_layer, false, INTERNAL_MODE_FRONT);
-				new_layer->force_parent_owned();
+				new_layer->set_as_tile_map_internal_node(index);
 				new_layer->set_name(vformat("Layer%d", index));
-				new_layer->set_layer_index_in_tile_map_node(index);
 				new_layer->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileMap::_emit_changed));
 				layers.push_back(new_layer);
 			}
@@ -795,46 +792,34 @@ Rect2i TileMap::get_used_rect() const {
 // --- Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems ---
 
 void TileMap::set_light_mask(int p_light_mask) {
-	// Occlusion: set light mask.
+	// Set light mask for occlusion and applies it to all layers too.
 	CanvasItem::set_light_mask(p_light_mask);
 	for (TileMapLayer *layer : layers) {
-		layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_LIGHT_MASK);
+		layer->set_light_mask(p_light_mask);
 	}
 }
 
-void TileMap::set_material(const Ref<Material> &p_material) {
-	// Set material for the whole tilemap.
-	CanvasItem::set_material(p_material);
-
-	// Update material for the whole tilemap.
+void TileMap::set_self_modulate(const Color &p_self_modulate) {
+	// Set self_modulation and applies it to all layers too.
+	CanvasItem::set_self_modulate(p_self_modulate);
 	for (TileMapLayer *layer : layers) {
-		layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_MATERIAL);
-	}
-}
-
-void TileMap::set_use_parent_material(bool p_use_parent_material) {
-	// Set use_parent_material for the whole tilemap.
-	CanvasItem::set_use_parent_material(p_use_parent_material);
-
-	// Update use_parent_material for the whole tilemap.
-	for (TileMapLayer *layer : layers) {
-		layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_USE_PARENT_MATERIAL);
+		layer->set_self_modulate(p_self_modulate);
 	}
 }
 
 void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
-	// Set a default texture filter for the whole tilemap.
+	// Set a default texture filter and applies it to all layers too.
 	CanvasItem::set_texture_filter(p_texture_filter);
 	for (TileMapLayer *layer : layers) {
-		layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_TEXTURE_FILTER);
+		layer->set_texture_filter(p_texture_filter);
 	}
 }
 
 void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
-	// Set a default texture repeat for the whole tilemap.
+	// Set a default texture repeat and applies it to all layers too.
 	CanvasItem::set_texture_repeat(p_texture_repeat);
 	for (TileMapLayer *layer : layers) {
-		layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_TILE_MAP_TEXTURE_REPEAT);
+		layer->set_texture_repeat(p_texture_repeat);
 	}
 }
 
@@ -1003,11 +988,10 @@ void TileMap::_bind_methods() {
 TileMap::TileMap() {
 	TileMapLayer *new_layer = memnew(TileMapLayer);
 	add_child(new_layer, false, INTERNAL_MODE_FRONT);
+	new_layer->set_as_tile_map_internal_node(0);
 	new_layer->set_name("Layer0");
-	new_layer->set_layer_index_in_tile_map_node(0);
 	new_layer->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileMap::_emit_changed));
 	layers.push_back(new_layer);
-
 	default_layer = memnew(TileMapLayer);
 }
 

+ 3 - 3
scene/2d/tile_map.h

@@ -46,9 +46,10 @@ enum TileMapDataFormat {
 };
 
 class TileMap : public TileMapLayerGroup {
-	GDCLASS(TileMap, TileMapLayerGroup);
+	GDCLASS(TileMap, TileMapLayerGroup)
 
 public:
+	// Kept for compatibility, but should use TileMapLayer::VisibilityMode instead.
 	enum VisibilityMode {
 		VISIBILITY_MODE_DEFAULT,
 		VISIBILITY_MODE_FORCE_SHOW,
@@ -187,8 +188,7 @@ public:
 
 	// Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems.
 	virtual void set_light_mask(int p_light_mask) override;
-	virtual void set_material(const Ref<Material> &p_material) override;
-	virtual void set_use_parent_material(bool p_use_parent_material) override;
+	virtual void set_self_modulate(const Color &p_self_modulate) override;
 	virtual void set_texture_filter(CanvasItem::TextureFilter p_texture_filter) override;
 	virtual void set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) override;
 

+ 221 - 117
scene/2d/tile_map_layer.cpp

@@ -40,10 +40,6 @@
 #include "servers/navigation_server_3d.h"
 #endif // DEBUG_ENABLED
 
-TileMap *TileMapLayer::_fetch_tilemap() const {
-	return TileMap::cast_to<TileMap>(get_parent());
-}
-
 #ifdef DEBUG_ENABLED
 /////////////////////////////// Debug //////////////////////////////////////////
 constexpr int TILE_MAP_DEBUG_QUADRANT_SIZE = 16;
@@ -183,7 +179,6 @@ void TileMapLayer::_debug_quadrants_update_cell(CellData &r_cell_data, SelfList<
 
 /////////////////////////////// Rendering //////////////////////////////////////
 void TileMapLayer::_rendering_update() {
-	const TileMap *tile_map_node = _fetch_tilemap();
 	const Ref<TileSet> &tile_set = get_effective_tile_set();
 	RenderingServer *rs = RenderingServer::get_singleton();
 
@@ -192,24 +187,23 @@ void TileMapLayer::_rendering_update() {
 
 	// ----------- Layer level processing -----------
 	if (!forced_cleanup) {
-		// Update the layer's CanvasItem.
-		set_use_parent_material(true);
-		set_light_mask(tile_map_node->get_light_mask());
-
 		// Modulate the layer.
 		Color layer_modulate = get_modulate();
 #ifdef TOOLS_ENABLED
-		const Vector<StringName> selected_layers = tile_map_node->get_selected_layers();
-		if (tile_map_node->is_highlighting_selected_layer() && selected_layers.size() == 1 && get_name() != selected_layers[0]) {
-			TileMapLayer *selected_layer = Object::cast_to<TileMapLayer>(tile_map_node->get_node_or_null(String(selected_layers[0])));
-			if (selected_layer) {
-				int z_selected = selected_layer->get_z_index();
-				int layer_z_index = get_z_index();
-				if (layer_z_index < z_selected || (layer_z_index == z_selected && get_index() < selected_layer->get_index())) {
-					layer_modulate = layer_modulate.darkened(0.5);
-				} else if (layer_z_index > z_selected || (layer_z_index == z_selected && get_index() > selected_layer->get_index())) {
-					layer_modulate = layer_modulate.darkened(0.5);
-					layer_modulate.a *= 0.3;
+		const TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(get_parent());
+		if (tile_map_layer_group) {
+			const Vector<StringName> selected_layers = tile_map_layer_group->get_selected_layers();
+			if (tile_map_layer_group->is_highlighting_selected_layer() && selected_layers.size() == 1 && get_name() != selected_layers[0]) {
+				TileMapLayer *selected_layer = Object::cast_to<TileMapLayer>(tile_map_layer_group->get_node_or_null(String(selected_layers[0])));
+				if (selected_layer) {
+					int z_selected = selected_layer->get_z_index();
+					int layer_z_index = get_z_index();
+					if (layer_z_index < z_selected || (layer_z_index == z_selected && get_index() < selected_layer->get_index())) {
+						layer_modulate = layer_modulate.darkened(0.5);
+					} else if (layer_z_index > z_selected || (layer_z_index == z_selected && get_index() > selected_layer->get_index())) {
+						layer_modulate = layer_modulate.darkened(0.5);
+						layer_modulate.a *= 0.3;
+					}
 				}
 			}
 		}
@@ -224,8 +218,8 @@ void TileMapLayer::_rendering_update() {
 
 	// Check if anything changed that might change the quadrant shape.
 	// If so, recreate everything.
-	bool quandrant_shape_changed = dirty.flags[DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE] ||
-			(is_y_sort_enabled() && (dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] || dirty.flags[DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_LOCAL_TRANSFORM] || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET]));
+	bool quandrant_shape_changed = dirty.flags[DIRTY_FLAGS_LAYER_RENDERING_QUADRANT_SIZE] ||
+			(is_y_sort_enabled() && (dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] || dirty.flags[DIRTY_FLAGS_LAYER_LOCAL_TRANSFORM] || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET]));
 
 	// Free all quadrants.
 	if (forced_cleanup || quandrant_shape_changed) {
@@ -330,7 +324,7 @@ void TileMapLayer::_rendering_update() {
 						Transform2D xform(0, rendering_quadrant->canvas_items_position);
 						rs->canvas_item_set_transform(ci, xform);
 
-						rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask());
+						rs->canvas_item_set_light_mask(ci, get_light_mask());
 						rs->canvas_item_set_z_as_relative_to_parent(ci, true);
 						rs->canvas_item_set_z_index(ci, tile_z_index);
 
@@ -398,17 +392,15 @@ void TileMapLayer::_rendering_update() {
 			}
 		}
 
-		// Updates on TileMap changes.
-		if (dirty.flags[DIRTY_FLAGS_TILE_MAP_LIGHT_MASK] ||
-				dirty.flags[DIRTY_FLAGS_TILE_MAP_USE_PARENT_MATERIAL] ||
-				dirty.flags[DIRTY_FLAGS_TILE_MAP_MATERIAL] ||
-				dirty.flags[DIRTY_FLAGS_TILE_MAP_TEXTURE_FILTER] ||
-				dirty.flags[DIRTY_FLAGS_TILE_MAP_TEXTURE_REPEAT] ||
+		// Updates on rendering changes.
+		if (dirty.flags[DIRTY_FLAGS_LAYER_LIGHT_MASK] ||
+				dirty.flags[DIRTY_FLAGS_LAYER_TEXTURE_FILTER] ||
+				dirty.flags[DIRTY_FLAGS_LAYER_TEXTURE_REPEAT] ||
 				dirty.flags[DIRTY_FLAGS_LAYER_SELF_MODULATE]) {
 			for (KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) {
 				Ref<RenderingQuadrant> &rendering_quadrant = kv.value;
 				for (const RID &ci : rendering_quadrant->canvas_items) {
-					rs->canvas_item_set_light_mask(ci, tile_map_node->get_light_mask());
+					rs->canvas_item_set_light_mask(ci, get_light_mask());
 					rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree()));
 					rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree()));
 					rs->canvas_item_set_self_modulate(ci, get_self_modulate());
@@ -465,7 +457,6 @@ void TileMapLayer::_rendering_notification(int p_what) {
 }
 
 void TileMapLayer::_rendering_quadrants_update_cell(CellData &r_cell_data, SelfList<RenderingQuadrant>::List &r_dirty_rendering_quadrant_list) {
-	const TileMap *tile_map_node = _fetch_tilemap();
 	const Ref<TileSet> &tile_set = get_effective_tile_set();
 
 	// Check if the cell is valid and retrieve its y_sort_origin.
@@ -495,14 +486,13 @@ void TileMapLayer::_rendering_quadrants_update_cell(CellData &r_cell_data, SelfL
 			canvas_items_position = Vector2(0, tile_set->map_to_local(r_cell_data.coords).y + tile_y_sort_origin + y_sort_origin);
 			quadrant_coords = canvas_items_position * 100;
 		} else {
-			int quad_size = tile_map_node->get_rendering_quadrant_size();
 			const Vector2i &coords = r_cell_data.coords;
 
 			// Rounding down, instead of simply rounding towards zero (truncating).
 			quadrant_coords = Vector2i(
-					coords.x > 0 ? coords.x / quad_size : (coords.x - (quad_size - 1)) / quad_size,
-					coords.y > 0 ? coords.y / quad_size : (coords.y - (quad_size - 1)) / quad_size);
-			canvas_items_position = tile_set->map_to_local(quad_size * quadrant_coords);
+					coords.x > 0 ? coords.x / rendering_quadrant_size : (coords.x - (rendering_quadrant_size - 1)) / rendering_quadrant_size,
+					coords.y > 0 ? coords.y / rendering_quadrant_size : (coords.y - (rendering_quadrant_size - 1)) / rendering_quadrant_size);
+			canvas_items_position = tile_set->map_to_local(rendering_quadrant_size * quadrant_coords);
 		}
 
 		Ref<RenderingQuadrant> rendering_quadrant;
@@ -767,7 +757,6 @@ void TileMapLayer::_physics_clear_cell(CellData &r_cell_data) {
 }
 
 void TileMapLayer::_physics_update_cell(CellData &r_cell_data) {
-	const TileMap *tile_map_node = _fetch_tilemap();
 	const Ref<TileSet> &tile_set = get_effective_tile_set();
 	Transform2D gl_transform = get_global_transform();
 	RID space = get_world_2d()->get_space();
@@ -825,7 +814,7 @@ void TileMapLayer::_physics_update_cell(CellData &r_cell_data) {
 							body = ps->body_create();
 						}
 						bodies_coords[body] = r_cell_data.coords;
-						ps->body_set_mode(body, tile_map_node->is_collision_animatable() ? PhysicsServer2D::BODY_MODE_KINEMATIC : PhysicsServer2D::BODY_MODE_STATIC);
+						ps->body_set_mode(body, use_kinematic_bodies ? PhysicsServer2D::BODY_MODE_KINEMATIC : PhysicsServer2D::BODY_MODE_STATIC);
 						ps->body_set_space(body, space);
 
 						Transform2D xform;
@@ -833,7 +822,7 @@ void TileMapLayer::_physics_update_cell(CellData &r_cell_data) {
 						xform = gl_transform * xform;
 						ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
 
-						ps->body_attach_object_instance_id(body, tile_map_node->get_instance_id());
+						ps->body_attach_object_instance_id(body, tile_map_node ? tile_map_node->get_instance_id() : get_instance_id());
 						ps->body_set_collision_layer(body, physics_layer);
 						ps->body_set_collision_mask(body, physics_mask);
 						ps->body_set_pickable(body, false);
@@ -885,7 +874,6 @@ void TileMapLayer::_physics_update_cell(CellData &r_cell_data) {
 #ifdef DEBUG_ENABLED
 void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data) {
 	// Draw the debug collision shapes.
-	TileMap *tile_map_node = _fetch_tilemap();
 	const Ref<TileSet> &tile_set = get_effective_tile_set();
 	ERR_FAIL_COND(!tile_set.is_valid());
 
@@ -894,14 +882,14 @@ void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vect
 	}
 
 	bool show_collision = false;
-	switch (tile_map_node->get_collision_visibility_mode()) {
-		case TileMap::VISIBILITY_MODE_DEFAULT:
+	switch (collision_visibility_mode) {
+		case TileMapLayer::VISIBILITY_MODE_DEFAULT:
 			show_collision = !Engine::get_singleton()->is_editor_hint() && get_tree()->is_debugging_collisions_hint();
 			break;
-		case TileMap::VISIBILITY_MODE_FORCE_HIDE:
+		case TileMapLayer::VISIBILITY_MODE_FORCE_HIDE:
 			show_collision = false;
 			break;
-		case TileMap::VISIBILITY_MODE_FORCE_SHOW:
+		case TileMapLayer::VISIBILITY_MODE_FORCE_SHOW:
 			show_collision = true;
 			break;
 	}
@@ -942,32 +930,32 @@ void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vect
 
 void TileMapLayer::_navigation_update() {
 	ERR_FAIL_NULL(NavigationServer2D::get_singleton());
-	const Ref<TileSet> &tile_set = get_effective_tile_set();
 	NavigationServer2D *ns = NavigationServer2D::get_singleton();
+	const Ref<TileSet> &tile_set = get_effective_tile_set();
 
 	// Check if we should cleanup everything.
 	bool forced_cleanup = in_destructor || !enabled || !navigation_enabled || !is_inside_tree() || !tile_set.is_valid();
 
 	// ----------- Layer level processing -----------
-	if (forced_cleanup) {
-		if (navigation_map.is_valid() && !uses_world_navigation_map) {
-			ns->free(navigation_map);
-			navigation_map = RID();
-		}
-	} else {
-		// Update navigation maps.
-		if (!navigation_map.is_valid()) {
-			if (layer_index_in_tile_map_node == 0) {
-				// Use the default World2D navigation map for the first layer when empty.
-				navigation_map = get_world_2d()->get_navigation_map();
-				uses_world_navigation_map = true;
-			} else {
-				RID new_layer_map = ns->map_create();
-				// Set the default NavigationPolygon cell_size on the new map as a mismatch causes an error.
-				ns->map_set_cell_size(new_layer_map, 1.0);
-				ns->map_set_active(new_layer_map, true);
-				navigation_map = new_layer_map;
-				uses_world_navigation_map = false;
+	// All this processing is kept for compatibility with the TileMap node.
+	// Otherwise, layers shall use the World2D navigation map or define a custom one with set_navigation_map(...).
+	if (tile_map_node) {
+		if (forced_cleanup) {
+			if (navigation_map_override.is_valid()) {
+				ns->free(navigation_map_override);
+				navigation_map_override = RID();
+			}
+		} else {
+			// Update navigation maps.
+			if (!navigation_map_override.is_valid()) {
+				if (layer_index_in_tile_map_node > 0) {
+					// Create a dedicated map for each layer.
+					RID new_layer_map = ns->map_create();
+					// Set the default NavigationPolygon cell_size on the new map as a mismatch causes an error.
+					ns->map_set_cell_size(new_layer_map, 1.0);
+					ns->map_set_active(new_layer_map, true);
+					navigation_map_override = new_layer_map;
+				}
 			}
 		}
 	}
@@ -979,7 +967,7 @@ void TileMapLayer::_navigation_update() {
 			_navigation_clear_cell(kv.value);
 		}
 	} else {
-		if (_navigation_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE]) {
+		if (_navigation_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE] || dirty.flags[DIRTY_FLAGS_LAYER_NAVIGATION_MAP]) {
 			// Update all cells.
 			for (KeyValue<Vector2i, CellData> &kv : tile_map) {
 				_navigation_update_cell(kv.value);
@@ -1033,10 +1021,11 @@ void TileMapLayer::_navigation_clear_cell(CellData &r_cell_data) {
 }
 
 void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) {
-	const TileMap *tile_map_node = _fetch_tilemap();
 	const Ref<TileSet> &tile_set = get_effective_tile_set();
 	NavigationServer2D *ns = NavigationServer2D::get_singleton();
 	Transform2D gl_xform = get_global_transform();
+	RID navigation_map = navigation_map_override.is_valid() ? navigation_map_override : get_world_2d()->get_navigation_map();
+	ERR_FAIL_COND(navigation_map.is_null());
 
 	// Get the navigation polygons and create regions.
 	TileMapCell &c = r_cell_data.cell;
@@ -1084,7 +1073,7 @@ void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) {
 						if (!region.is_valid()) {
 							region = ns->region_create();
 						}
-						ns->region_set_owner_id(region, tile_map_node->get_instance_id());
+						ns->region_set_owner_id(region, tile_map_node ? tile_map_node->get_instance_id() : get_instance_id());
 						ns->region_set_map(region, navigation_map);
 						ns->region_set_transform(region, gl_xform * tile_transform);
 						ns->region_set_navigation_layers(region, tile_set->get_navigation_layer_layers(navigation_layer_index));
@@ -1111,16 +1100,15 @@ void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) {
 #ifdef DEBUG_ENABLED
 void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data) {
 	// Draw the debug collision shapes.
-	const TileMap *tile_map_node = _fetch_tilemap();
 	bool show_navigation = false;
-	switch (tile_map_node->get_navigation_visibility_mode()) {
-		case TileMap::VISIBILITY_MODE_DEFAULT:
+	switch (navigation_visibility_mode) {
+		case TileMapLayer::VISIBILITY_MODE_DEFAULT:
 			show_navigation = !Engine::get_singleton()->is_editor_hint() && get_tree()->is_debugging_navigation_hint();
 			break;
-		case TileMap::VISIBILITY_MODE_FORCE_HIDE:
+		case TileMapLayer::VISIBILITY_MODE_FORCE_HIDE:
 			show_navigation = false;
 			break;
-		case TileMap::VISIBILITY_MODE_FORCE_SHOW:
+		case TileMapLayer::VISIBILITY_MODE_FORCE_SHOW:
 			show_navigation = true;
 			break;
 	}
@@ -1250,13 +1238,14 @@ void TileMapLayer::_scenes_update() {
 }
 
 void TileMapLayer::_scenes_clear_cell(CellData &r_cell_data) {
-	const TileMap *tile_map_node = _fetch_tilemap();
-	if (!tile_map_node) {
-		return;
-	}
-
 	// Cleanup existing scene.
-	Node *node = tile_map_node->get_node_or_null(r_cell_data.scene);
+	Node *node = nullptr;
+	if (tile_map_node) {
+		// Compatibility with TileMap.
+		node = tile_map_node->get_node_or_null(r_cell_data.scene);
+	} else {
+		node = get_node_or_null(r_cell_data.scene);
+	}
 	if (node) {
 		node->queue_free();
 	}
@@ -1264,7 +1253,6 @@ void TileMapLayer::_scenes_clear_cell(CellData &r_cell_data) {
 }
 
 void TileMapLayer::_scenes_update_cell(CellData &r_cell_data) {
-	TileMap *tile_map_node = _fetch_tilemap();
 	const Ref<TileSet> &tile_set = get_effective_tile_set();
 
 	// Clear the scene in any case.
@@ -1292,7 +1280,12 @@ void TileMapLayer::_scenes_update_cell(CellData &r_cell_data) {
 						xform.set_origin(tile_set->map_to_local(r_cell_data.coords));
 						scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform());
 					}
-					tile_map_node->add_child(scene);
+					if (tile_map_node) {
+						// Compatibility with TileMap.
+						tile_map_node->add_child(scene);
+					} else {
+						add_child(scene);
+					}
 					r_cell_data.scene = scene->get_name();
 				}
 			}
@@ -1352,26 +1345,28 @@ void TileMapLayer::_scenes_draw_cell_debug(const RID &p_canvas_item, const Vecto
 /////////////////////////////////////////////////////////////////////
 
 void TileMapLayer::_build_runtime_update_tile_data() {
-	const TileMap *tile_map_node = _fetch_tilemap();
 	const Ref<TileSet> &tile_set = get_effective_tile_set();
 
 	// Check if we should cleanup everything.
 	bool forced_cleanup = in_destructor || !enabled || !tile_set.is_valid() || !is_visible_in_tree();
 	if (!forced_cleanup) {
-		if (tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update)) {
+		bool valid_runtime_update = GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update);
+		bool valid_runtime_update_for_tilemap = tile_map_node && tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update); // For keeping compatibility.
+		if (valid_runtime_update || valid_runtime_update_for_tilemap) {
+			bool use_tilemap_for_runtime = valid_runtime_update_for_tilemap && !valid_runtime_update;
 			if (_runtime_update_tile_data_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET]) {
 				_runtime_update_needs_all_cells_cleaned_up = true;
 				for (KeyValue<Vector2i, CellData> &E : tile_map) {
-					_build_runtime_update_tile_data_for_cell(E.value);
+					_build_runtime_update_tile_data_for_cell(E.value, use_tilemap_for_runtime);
 				}
-			} else if (dirty.flags[DIRTY_FLAGS_TILE_MAP_RUNTIME_UPDATE]) {
+			} else if (dirty.flags[DIRTY_FLAGS_LAYER_RUNTIME_UPDATE]) {
 				for (KeyValue<Vector2i, CellData> &E : tile_map) {
-					_build_runtime_update_tile_data_for_cell(E.value, true);
+					_build_runtime_update_tile_data_for_cell(E.value, use_tilemap_for_runtime, true);
 				}
 			} else {
 				for (SelfList<CellData> *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();
-					_build_runtime_update_tile_data_for_cell(cell_data);
+					_build_runtime_update_tile_data_for_cell(cell_data, use_tilemap_for_runtime);
 				}
 			}
 		}
@@ -1382,8 +1377,7 @@ void TileMapLayer::_build_runtime_update_tile_data() {
 	_runtime_update_tile_data_was_cleaned_up = forced_cleanup;
 }
 
-void TileMapLayer::_build_runtime_update_tile_data_for_cell(CellData &r_cell_data, bool p_auto_add_to_dirty_list) {
-	TileMap *tile_map_node = _fetch_tilemap();
+void TileMapLayer::_build_runtime_update_tile_data_for_cell(CellData &r_cell_data, bool p_use_tilemap_for_runtime, bool p_auto_add_to_dirty_list) {
 	const Ref<TileSet> &tile_set = get_effective_tile_set();
 
 	TileMapCell &c = r_cell_data.cell;
@@ -1395,18 +1389,37 @@ void TileMapLayer::_build_runtime_update_tile_data_for_cell(CellData &r_cell_dat
 			TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
 			if (atlas_source) {
 				bool ret = false;
-				if (tile_map_node->GDVIRTUAL_CALL(_use_tile_data_runtime_update, layer_index_in_tile_map_node, r_cell_data.coords, ret) && ret) {
-					TileData *tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
 
-					// Create the runtime TileData.
-					TileData *tile_data_runtime_use = tile_data->duplicate();
-					tile_data_runtime_use->set_allow_transform(true);
-					r_cell_data.runtime_tile_data_cache = tile_data_runtime_use;
+				if (p_use_tilemap_for_runtime) {
+					// Compatibility with TileMap.
+					if (tile_map_node->GDVIRTUAL_CALL(_use_tile_data_runtime_update, layer_index_in_tile_map_node, r_cell_data.coords, ret) && ret) {
+						TileData *tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
+
+						// Create the runtime TileData.
+						TileData *tile_data_runtime_use = tile_data->duplicate();
+						tile_data_runtime_use->set_allow_transform(true);
+						r_cell_data.runtime_tile_data_cache = tile_data_runtime_use;
 
-					tile_map_node->GDVIRTUAL_CALL(_tile_data_runtime_update, layer_index_in_tile_map_node, r_cell_data.coords, tile_data_runtime_use);
+						tile_map_node->GDVIRTUAL_CALL(_tile_data_runtime_update, layer_index_in_tile_map_node, r_cell_data.coords, tile_data_runtime_use);
 
-					if (p_auto_add_to_dirty_list) {
-						dirty.cell_list.add(&r_cell_data.dirty_list_element);
+						if (p_auto_add_to_dirty_list) {
+							dirty.cell_list.add(&r_cell_data.dirty_list_element);
+						}
+					}
+				} else {
+					if (GDVIRTUAL_CALL(_use_tile_data_runtime_update, r_cell_data.coords, ret) && ret) {
+						TileData *tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
+
+						// Create the runtime TileData.
+						TileData *tile_data_runtime_use = tile_data->duplicate();
+						tile_data_runtime_use->set_allow_transform(true);
+						r_cell_data.runtime_tile_data_cache = tile_data_runtime_use;
+
+						GDVIRTUAL_CALL(_tile_data_runtime_update, r_cell_data.coords, tile_data_runtime_use);
+
+						if (p_auto_add_to_dirty_list) {
+							dirty.cell_list.add(&r_cell_data.dirty_list_element);
+						}
 					}
 				}
 			}
@@ -1611,8 +1624,7 @@ void TileMapLayer::_renamed() {
 }
 
 void TileMapLayer::_update_notify_local_transform() {
-	TileMap *tile_map_node = _fetch_tilemap();
-	bool notify = tile_map_node->is_collision_animatable() || is_y_sort_enabled();
+	bool notify = is_using_kinematic_bodies() || is_y_sort_enabled();
 	if (!notify) {
 		if (is_y_sort_enabled()) {
 			notify = true;
@@ -1727,16 +1739,23 @@ void TileMapLayer::_notification(int p_what) {
 void TileMapLayer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMapLayer::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(0));
 
+	GDVIRTUAL_BIND(_use_tile_data_runtime_update, "coords");
+	GDVIRTUAL_BIND(_tile_data_runtime_update, "coords", "tile_data");
+
 	ADD_SIGNAL(MethodInfo(CoreStringNames::get_singleton()->changed));
 }
 
-void TileMapLayer::set_layer_index_in_tile_map_node(int p_index) {
-	if (p_index == layer_index_in_tile_map_node) {
-		return;
+void TileMapLayer::set_as_tile_map_internal_node(int p_index) {
+	// Compatibility with TileMap.
+	ERR_FAIL_NULL(get_parent());
+	tile_map_node = Object::cast_to<TileMap>(get_parent());
+	set_use_parent_material(true);
+	force_parent_owned();
+	if (layer_index_in_tile_map_node != p_index) {
+		layer_index_in_tile_map_node = p_index;
+		dirty.flags[DIRTY_FLAGS_LAYER_INDEX_IN_TILE_MAP_NODE] = true;
+		_queue_internal_update();
 	}
-	layer_index_in_tile_map_node = p_index;
-	dirty.flags[DIRTY_FLAGS_LAYER_INDEX_IN_TILE_MAP_NODE] = true;
-	_queue_internal_update();
 }
 
 Rect2 TileMapLayer::get_rect(bool &r_changed) const {
@@ -2085,7 +2104,7 @@ void TileMapLayer::set_tile_data(TileMapDataFormat p_format, const Vector<int> &
 	clear();
 
 #ifdef DISABLE_DEPRECATED
-	ERR_FAIL_COND_MSG(p_format != TileMapDataFormat::FORMAT_3, vformat("Cannot handle deprecated TileMap data format version %d. This Godot version was compiled with no support for deprecated data.", p_format));
+	ERR_FAIL_COND_MSG(p_format != TileMapDataFormat::FORMAT_3, vformat("Cannot handle deprecated TileMapLayer data format version %d. This Godot version was compiled with no support for deprecated data.", p_format));
 #endif
 
 	for (int i = 0; i < c; i += offset) {
@@ -2176,7 +2195,7 @@ Vector<int> TileMapLayer::get_tile_data() const {
 	return tile_data;
 }
 
-void TileMapLayer::notify_tile_map_change(DirtyFlags p_what) {
+void TileMapLayer::notify_tile_map_layer_group_change(DirtyFlags p_what) {
 	if (p_what == DIRTY_FLAGS_LAYER_GROUP_SELECTED_LAYERS ||
 			p_what == DIRTY_FLAGS_LAYER_GROUP_HIGHLIGHT_SELECTED ||
 			p_what == DIRTY_FLAGS_LAYER_GROUP_TILE_SET) {
@@ -2192,6 +2211,12 @@ void TileMapLayer::update_internals() {
 	_deferred_internal_update();
 }
 
+void TileMapLayer::notify_runtime_tile_data_update() {
+	dirty.flags[TileMapLayer::DIRTY_FLAGS_LAYER_RUNTIME_UPDATE] = true;
+	_queue_internal_update();
+	emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
 void TileMapLayer::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) {
 	// Set the current cell tile (using integer position).
 	Vector2i pk(p_coords);
@@ -2532,8 +2557,9 @@ void TileMapLayer::set_enabled(bool p_enabled) {
 	_queue_internal_update();
 	emit_signal(CoreStringNames::get_singleton()->changed);
 
-	TileMap *tile_map_node = _fetch_tilemap();
-	tile_map_node->update_configuration_warnings();
+	if (tile_map_node) {
+		tile_map_node->update_configuration_warnings();
+	}
 }
 
 bool TileMapLayer::is_enabled() const {
@@ -2559,8 +2585,9 @@ void TileMapLayer::set_y_sort_enabled(bool p_y_sort_enabled) {
 	_queue_internal_update();
 	emit_signal(CoreStringNames::get_singleton()->changed);
 
-	TileMap *tile_map_node = _fetch_tilemap();
-	tile_map_node->update_configuration_warnings();
+	if (tile_map_node) {
+		tile_map_node->update_configuration_warnings();
+	}
 	_update_notify_local_transform();
 }
 
@@ -2587,8 +2614,51 @@ void TileMapLayer::set_z_index(int p_z_index) {
 	_queue_internal_update();
 	emit_signal(CoreStringNames::get_singleton()->changed);
 
-	TileMap *tile_map_node = _fetch_tilemap();
-	tile_map_node->update_configuration_warnings();
+	if (tile_map_node) {
+		tile_map_node->update_configuration_warnings();
+	}
+}
+
+void TileMapLayer::set_light_mask(int p_light_mask) {
+	if (get_light_mask() == p_light_mask) {
+		return;
+	}
+	CanvasItem::set_light_mask(p_light_mask);
+	dirty.flags[DIRTY_FLAGS_LAYER_LIGHT_MASK] = true;
+	_queue_internal_update();
+	emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+void TileMapLayer::set_texture_filter(TextureFilter p_texture_filter) {
+	// Set a default texture filter for the whole tilemap.
+	CanvasItem::set_texture_filter(p_texture_filter);
+	dirty.flags[DIRTY_FLAGS_LAYER_TEXTURE_FILTER] = true;
+	_queue_internal_update();
+	emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+void TileMapLayer::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
+	// Set a default texture repeat for the whole tilemap.
+	CanvasItem::set_texture_repeat(p_texture_repeat);
+	dirty.flags[DIRTY_FLAGS_LAYER_TEXTURE_REPEAT] = true;
+	_queue_internal_update();
+	emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+void TileMapLayer::set_rendering_quadrant_size(int p_size) {
+	if (rendering_quadrant_size == p_size) {
+		return;
+	}
+	dirty.flags[DIRTY_FLAGS_LAYER_RENDERING_QUADRANT_SIZE] = true;
+	ERR_FAIL_COND_MSG(p_size < 1, "TileMapQuadrant size cannot be smaller than 1.");
+
+	rendering_quadrant_size = p_size;
+	_queue_internal_update();
+	emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+int TileMapLayer::get_rendering_quadrant_size() const {
+	return rendering_quadrant_size;
 }
 
 void TileMapLayer::set_use_kinematic_bodies(bool p_use_kinematic_bodies) {
@@ -2602,6 +2672,20 @@ bool TileMapLayer::is_using_kinematic_bodies() const {
 	return use_kinematic_bodies;
 }
 
+void TileMapLayer::set_collision_visibility_mode(TileMapLayer::VisibilityMode p_show_collision) {
+	if (collision_visibility_mode == p_show_collision) {
+		return;
+	}
+	collision_visibility_mode = p_show_collision;
+	dirty.flags[DIRTY_FLAGS_LAYER_COLLISION_VISIBILITY_MODE] = true;
+	_queue_internal_update();
+	emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+TileMapLayer::VisibilityMode TileMapLayer::get_collision_visibility_mode() const {
+	return collision_visibility_mode;
+}
+
 void TileMapLayer::set_navigation_enabled(bool p_enabled) {
 	if (navigation_enabled == p_enabled) {
 		return;
@@ -2617,18 +2701,38 @@ bool TileMapLayer::is_navigation_enabled() const {
 }
 
 void TileMapLayer::set_navigation_map(RID p_map) {
-	ERR_FAIL_COND_MSG(!is_inside_tree(), "A TileMap navigation map can only be changed while inside the SceneTree.");
-	navigation_map = p_map;
-	uses_world_navigation_map = p_map == get_world_2d()->get_navigation_map();
+	if (navigation_map_override == p_map) {
+		return;
+	}
+	navigation_map_override = p_map;
+	dirty.flags[DIRTY_FLAGS_LAYER_NAVIGATION_MAP] = true;
+	_queue_internal_update();
+	emit_signal(CoreStringNames::get_singleton()->changed);
 }
 
 RID TileMapLayer::get_navigation_map() const {
-	if (navigation_map.is_valid()) {
-		return navigation_map;
+	if (navigation_map_override.is_valid()) {
+		return navigation_map_override;
+	} else if (is_inside_tree()) {
+		return get_world_2d()->get_navigation_map();
 	}
 	return RID();
 }
 
+void TileMapLayer::set_navigation_visibility_mode(TileMapLayer::VisibilityMode p_show_navigation) {
+	if (navigation_visibility_mode == p_show_navigation) {
+		return;
+	}
+	navigation_visibility_mode = p_show_navigation;
+	dirty.flags[DIRTY_FLAGS_LAYER_NAVIGATION_VISIBILITY_MODE] = true;
+	_queue_internal_update();
+	emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+TileMapLayer::VisibilityMode TileMapLayer::get_navigation_visibility_mode() const {
+	return navigation_visibility_mode;
+}
+
 void TileMapLayer::fix_invalid_tiles() {
 	Ref<TileSet> tileset = get_effective_tile_set();
 	ERR_FAIL_COND_MSG(tileset.is_null(), "Cannot call fix_invalid_tiles() on a TileMap without a valid TileSet.");

+ 44 - 20
scene/2d/tile_map_layer.h

@@ -218,6 +218,12 @@ class TileMapLayer : public Node2D {
 	GDCLASS(TileMapLayer, Node2D);
 
 public:
+	enum VisibilityMode {
+		VISIBILITY_MODE_DEFAULT,
+		VISIBILITY_MODE_FORCE_SHOW,
+		VISIBILITY_MODE_FORCE_HIDE,
+	};
+
 	enum DirtyFlags {
 		DIRTY_FLAGS_LAYER_ENABLED = 0,
 		DIRTY_FLAGS_LAYER_IN_TREE,
@@ -228,24 +234,23 @@ public:
 		DIRTY_FLAGS_LAYER_Y_SORT_ENABLED,
 		DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN,
 		DIRTY_FLAGS_LAYER_Z_INDEX,
+		DIRTY_FLAGS_LAYER_LIGHT_MASK,
+		DIRTY_FLAGS_LAYER_TEXTURE_FILTER,
+		DIRTY_FLAGS_LAYER_TEXTURE_REPEAT,
+		DIRTY_FLAGS_LAYER_RENDERING_QUADRANT_SIZE,
 		DIRTY_FLAGS_LAYER_USE_KINEMATIC_BODIES,
+		DIRTY_FLAGS_LAYER_COLLISION_VISIBILITY_MODE,
 		DIRTY_FLAGS_LAYER_NAVIGATION_ENABLED,
-		DIRTY_FLAGS_LAYER_INDEX_IN_TILE_MAP_NODE,
+		DIRTY_FLAGS_LAYER_NAVIGATION_MAP,
+		DIRTY_FLAGS_LAYER_NAVIGATION_VISIBILITY_MODE,
+		DIRTY_FLAGS_LAYER_RUNTIME_UPDATE,
+
+		DIRTY_FLAGS_LAYER_INDEX_IN_TILE_MAP_NODE, // For compatibility.
 
 		DIRTY_FLAGS_LAYER_GROUP_SELECTED_LAYERS,
 		DIRTY_FLAGS_LAYER_GROUP_HIGHLIGHT_SELECTED,
 		DIRTY_FLAGS_LAYER_GROUP_TILE_SET,
 
-		DIRTY_FLAGS_TILE_MAP_LIGHT_MASK,
-		DIRTY_FLAGS_TILE_MAP_MATERIAL,
-		DIRTY_FLAGS_TILE_MAP_USE_PARENT_MATERIAL,
-		DIRTY_FLAGS_TILE_MAP_TEXTURE_FILTER,
-		DIRTY_FLAGS_TILE_MAP_TEXTURE_REPEAT,
-		DIRTY_FLAGS_TILE_MAP_QUADRANT_SIZE,
-		DIRTY_FLAGS_TILE_MAP_COLLISION_VISIBILITY_MODE,
-		DIRTY_FLAGS_TILE_MAP_NAVIGATION_VISIBILITY_MODE,
-		DIRTY_FLAGS_TILE_MAP_Y_SORT_ENABLED,
-		DIRTY_FLAGS_TILE_MAP_RUNTIME_UPDATE,
 		DIRTY_FLAGS_MAX,
 	};
 
@@ -253,16 +258,23 @@ private:
 	// Exposed properties.
 	bool enabled = true;
 	int y_sort_origin = 0;
+	int rendering_quadrant_size = 16;
+
 	bool use_kinematic_bodies = false;
+	VisibilityMode collision_visibility_mode = VISIBILITY_MODE_DEFAULT;
+
 	bool navigation_enabled = true;
-	RID navigation_map;
-	bool uses_world_navigation_map = false;
+	RID navigation_map_override;
+	VisibilityMode navigation_visibility_mode = VISIBILITY_MODE_DEFAULT;
 
 	// Internal.
-	int layer_index_in_tile_map_node = -1;
 	HashMap<Vector2i, CellData> tile_map;
 	bool pending_update = false;
 
+	// For keeping compatibility with TileMap.
+	TileMap *tile_map_node = nullptr;
+	int layer_index_in_tile_map_node = -1;
+
 	// Dirty flag. Allows knowing what was modified since the last update.
 	struct {
 		bool flags[DIRTY_FLAGS_MAX] = { false };
@@ -276,13 +288,10 @@ private:
 	mutable Rect2i used_rect_cache;
 	mutable bool used_rect_cache_dirty = true;
 
-	// Method to fetch the TileSet to use
-	TileMap *_fetch_tilemap() const;
-
 	// Runtime tile data.
 	bool _runtime_update_tile_data_was_cleaned_up = false;
 	void _build_runtime_update_tile_data();
-	void _build_runtime_update_tile_data_for_cell(CellData &r_cell_data, bool p_auto_add_to_dirty_list = false);
+	void _build_runtime_update_tile_data_for_cell(CellData &r_cell_data, bool p_use_tilemap_for_runtime, bool p_auto_add_to_dirty_list = false);
 	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);
@@ -353,7 +362,7 @@ protected:
 
 public:
 	// TileMap node.
-	void set_layer_index_in_tile_map_node(int p_index);
+	void set_as_tile_map_internal_node(int p_index);
 
 	// Rect caching.
 	Rect2 get_rect(bool &r_changed) const;
@@ -370,9 +379,10 @@ public:
 	// For TileMap node's use.
 	void set_tile_data(TileMapDataFormat p_format, const Vector<int> &p_data);
 	Vector<int> get_tile_data() const;
-	void notify_tile_map_change(DirtyFlags p_what);
+	void notify_tile_map_layer_group_change(DirtyFlags p_what);
 
 	void update_internals();
+	void notify_runtime_tile_data_update();
 
 	// --- Exposed in TileMap ---
 	// Cells manipulation.
@@ -406,12 +416,23 @@ public:
 	void set_y_sort_origin(int p_y_sort_origin);
 	int get_y_sort_origin() const;
 	virtual void set_z_index(int p_z_index) override;
+	virtual void set_light_mask(int p_light_mask) override;
+	virtual void set_texture_filter(CanvasItem::TextureFilter p_texture_filter) override;
+	virtual void set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) override;
+	void set_rendering_quadrant_size(int p_size);
+	int get_rendering_quadrant_size() const;
+
 	void set_use_kinematic_bodies(bool p_use_kinematic_bodies);
 	bool is_using_kinematic_bodies() const;
+	void set_collision_visibility_mode(VisibilityMode p_show_collision);
+	VisibilityMode get_collision_visibility_mode() const;
+
 	void set_navigation_enabled(bool p_enabled);
 	bool is_navigation_enabled() const;
 	void set_navigation_map(RID p_map);
 	RID get_navigation_map() const;
+	void set_navigation_visibility_mode(VisibilityMode p_show_navigation);
+	VisibilityMode get_navigation_visibility_mode() const;
 
 	// Fixing and clearing methods.
 	void fix_invalid_tiles();
@@ -423,6 +444,9 @@ public:
 	// Helper.
 	Ref<TileSet> get_effective_tile_set() const;
 
+	// Virtual function to modify the TileData at runtime.
+	GDVIRTUAL1R(bool, _use_tile_data_runtime_update, Vector2i);
+	GDVIRTUAL2(_tile_data_runtime_update, Vector2i, TileData *);
 	// ---
 
 	TileMapLayer();

+ 4 - 4
scene/2d/tile_map_layer_group.cpp

@@ -53,7 +53,7 @@ void TileMapLayerGroup::_tile_set_changed() {
 	for (int i = 0; i < get_child_count(); i++) {
 		TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i));
 		if (layer) {
-			layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_TILE_SET);
+			layer->notify_tile_map_layer_group_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_TILE_SET);
 		}
 	}
 
@@ -70,7 +70,7 @@ void TileMapLayerGroup::set_selected_layers(Vector<StringName> p_layer_names) {
 	for (int i = 0; i < get_child_count(); i++) {
 		TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i));
 		if (layer) {
-			layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_SELECTED_LAYERS);
+			layer->notify_tile_map_layer_group_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_SELECTED_LAYERS);
 		}
 	}
 }
@@ -89,7 +89,7 @@ void TileMapLayerGroup::set_highlight_selected_layer(bool p_highlight_selected_l
 	for (int i = 0; i < get_child_count(); i++) {
 		TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i));
 		if (layer) {
-			layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_HIGHLIGHT_SELECTED);
+			layer->notify_tile_map_layer_group_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_HIGHLIGHT_SELECTED);
 		}
 	}
 }
@@ -132,7 +132,7 @@ void TileMapLayerGroup::set_tileset(const Ref<TileSet> &p_tileset) {
 	for (int i = 0; i < get_child_count(); i++) {
 		TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i));
 		if (layer) {
-			layer->notify_tile_map_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_TILE_SET);
+			layer->notify_tile_map_layer_group_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_TILE_SET);
 		}
 	}
 }