Repository: godotengine/godot
File: scene/3d/path_3d.cpp (C++)

Code before:
#include "core/config/project_settings.h"

bool PathDebug3D::debug_enabled = true;
Color PathDebug3D::debug_paths_color = Color(0.1, 1.0, 0.7, 0.4);
float PathDebug3D::debug_paths_sample_interval = 0.1;
bool PathDebug3D::debug_paths_fish_bones_enabled = true;
int PathDebug3D::debug_paths_fish_bones_interval = 4;
Ref<Material> PathDebug3D::debug_default_material;

Mutex PathDebug3D::update_callbacks_mutex;
HashMap<Path3D *, Callable> PathDebug3D::update_callbacks;

void PathDebug3D::add_update_callback(Path3D *p_path, Callable p_callback) {
	MutexLock lock(update_callbacks_mutex);
	update_callbacks.insert(p_path, p_callback);
}

void PathDebug3D::remove_update_callback(Path3D *p_path) {
	MutexLock lock(update_callbacks_mutex);
	update_callbacks.erase(p_path);
}

void PathDebug3D::emit_update_callbacks() {
	MutexLock lock(update_callbacks_mutex);
	for (KeyValue<Path3D *, Callable> &kv : update_callbacks) {
		ERR_CONTINUE(kv.value.is_null());
		kv.value.call();
	}
}

void PathDebug3D::init_settings() {
#ifndef DISABLE_DEPRECATED
	if (!ProjectSettings::get_singleton()->has_setting("debug/shapes/paths/3d/geometry_color") && ProjectSettings::get_singleton()->has_setting("debug/shapes/paths/geometry_color")) {
		Color legacy_geometry_color = GLOBAL_GET("debug/shapes/paths/geometry_color");

		ProjectSettings::get_singleton()->set_setting("debug/shapes/paths/3d/geometry_color", legacy_geometry_color);
		ProjectSettings::get_singleton()->clear("debug/shapes/paths/geometry_color");
	}
#endif // DISABLE_DEPRECATED

	debug_paths_color = GLOBAL_DEF("debug/shapes/paths/3d/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
	debug_paths_sample_interval = GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "debug/shapes/paths/3d/sample_interval", PROPERTY_HINT_RANGE, "0.1,10,0.001,or_greater"), 0.1);
	debug_paths_fish_bones_enabled = GLOBAL_DEF(PropertyInfo(Variant::BOOL, "debug/shapes/paths/3d/fish_bones_enabled"), true);
	debug_paths_fish_bones_interval = GLOBAL_DEF(PropertyInfo(Variant::INT, "debug/shapes/paths/3d/fish_bones_interval", PROPERTY_HINT_RANGE, "1,10,1,or_greater"), 4);
}

void PathDebug3D::init_materials() {
	if (debug_default_material.is_valid()) {
		return;
	}
	Ref<StandardMaterial3D> debug_material;

Review comment (suggestion):
```suggestion
		ERR_CONTINUE(!kv.value.is_valid());
```

Code after:
Path3D::Path3D() {
	SceneTree *st = SceneTree::get_singleton();
	if (st && st->is_debugging_paths_hint()) {
		debug_instance = RS::get_singleton()->instance_create();
		set_notify_transform(true);
		_update_debug_mesh();
	}
}

Path3D::~Path3D() {
	if (debug_instance.is_valid()) {
		ERR_FAIL_NULL(RenderingServer::get_singleton());
		RS::get_singleton()->free(debug_instance);
	}
	if (debug_mesh.is_valid()) {
		ERR_FAIL_NULL(RenderingServer::get_singleton());
		RS::get_singleton()->free(debug_mesh->get_rid());
	}
}

void Path3D::set_update_callback(Callable p_callback) {
	update_callback = p_callback;
}

void Path3D::_notification(int p_what) {
	switch (p_what) {
		case NOTIFICATION_ENTER_TREE: {
			SceneTree *st = SceneTree::get_singleton();
			if (st && st->is_debugging_paths_hint()) {
				_update_debug_mesh();
			}
		} break;

		case NOTIFICATION_EXIT_TREE: {
			SceneTree *st = SceneTree::get_singleton();
			if (st && st->is_debugging_paths_hint()) {
				RS::get_singleton()->instance_set_visible(debug_instance, false);
			}
		} break;

		case NOTIFICATION_TRANSFORM_CHANGED: {
			if (is_inside_tree()) {
				if (debug_instance.is_valid()) {
					RS::get_singleton()->instance_set_transform(debug_instance, get_global_transform());
				}

				update_callback.call();
			}
		} break;
	}
}