|
31 | 31 | #include "gdscript_language_protocol.h"
|
32 | 32 |
|
33 | 33 | #include "core/config/project_settings.h"
|
| 34 | +#include "core/error/error_list.h" |
| 35 | +#include "core/io/resource_loader.h" |
34 | 36 | #include "editor/doc_tools.h"
|
35 | 37 | #include "editor/editor_help.h"
|
36 | 38 | #include "editor/editor_log.h"
|
37 | 39 | #include "editor/editor_node.h"
|
38 | 40 | #include "editor/editor_settings.h"
|
| 41 | +#include "scene/resources/packed_scene.h" |
39 | 42 |
|
40 | 43 | GDScriptLanguageProtocol *GDScriptLanguageProtocol::singleton = nullptr;
|
41 | 44 |
|
@@ -136,6 +139,7 @@ Error GDScriptLanguageProtocol::on_client_connected() {
|
136 | 139 |
|
137 | 140 | void GDScriptLanguageProtocol::on_client_disconnected(const int &p_client_id) {
|
138 | 141 | clients.erase(p_client_id);
|
| 142 | + scene_cache.clear(); |
139 | 143 | EditorNode::get_log()->add_message("[LSP] Disconnected", EditorLog::MSG_TYPE_EDITOR);
|
140 | 144 | }
|
141 | 145 |
|
@@ -236,6 +240,8 @@ void GDScriptLanguageProtocol::poll(int p_limit_usec) {
|
236 | 240 | on_client_connected();
|
237 | 241 | }
|
238 | 242 |
|
| 243 | + scene_cache._check_thread_for_cache_update(); |
| 244 | + |
239 | 245 | HashMap<int, Ref<LSPeer>>::Iterator E = clients.begin();
|
240 | 246 | while (E != clients.end()) {
|
241 | 247 | Ref<LSPeer> peer = E->value;
|
@@ -281,7 +287,7 @@ void GDScriptLanguageProtocol::stop() {
|
281 | 287 | Ref<LSPeer> peer = clients.get(E.key);
|
282 | 288 | peer->connection->disconnect_from_host();
|
283 | 289 | }
|
284 |
| - |
| 290 | + scene_cache.clear(); |
285 | 291 | server->stop();
|
286 | 292 | }
|
287 | 293 |
|
@@ -345,4 +351,209 @@ GDScriptLanguageProtocol::GDScriptLanguageProtocol() {
|
345 | 351 | set_scope("completionItem", text_document.ptr());
|
346 | 352 | set_scope("workspace", workspace.ptr());
|
347 | 353 | workspace->root = ProjectSettings::get_singleton()->get_resource_path();
|
| 354 | + scene_cache.workspace = workspace; |
| 355 | +} |
| 356 | + |
| 357 | +void SceneCache::_get_owners(EditorFileSystemDirectory *p_efsd, const String &p_path, List<String> &r_owners) { |
| 358 | + if (!p_efsd) { |
| 359 | + return; |
| 360 | + } |
| 361 | + |
| 362 | + for (int i = 0; i < p_efsd->get_subdir_count(); i++) { |
| 363 | + _get_owners(p_efsd->get_subdir(i), p_path, r_owners); |
| 364 | + } |
| 365 | + |
| 366 | + for (int i = 0; i < p_efsd->get_file_count(); i++) { |
| 367 | + Vector<String> deps = p_efsd->get_file_deps(i); |
| 368 | + bool found = false; |
| 369 | + for (int j = 0; j < deps.size(); j++) { |
| 370 | + if (deps[j] == p_path) { |
| 371 | + found = true; |
| 372 | + break; |
| 373 | + } |
| 374 | + } |
| 375 | + if (!found) { |
| 376 | + continue; |
| 377 | + } |
| 378 | + |
| 379 | + r_owners.push_back(p_efsd->get_file_path(i)); |
| 380 | + } |
| 381 | +} |
| 382 | + |
| 383 | +void SceneCache::_set_owner_scene_node(const String &p_path) { |
| 384 | + if (cache.has(p_path)) { |
| 385 | + return; |
| 386 | + } |
| 387 | + |
| 388 | + Node *owner_scene_node = nullptr; |
| 389 | + List<String> owners; |
| 390 | + |
| 391 | + _get_owners(EditorFileSystem::get_singleton()->get_filesystem(), p_path, owners); |
| 392 | + owners_path_cache[p_path] = owners; |
| 393 | + |
| 394 | + for (const String &owner : owners) { |
| 395 | + NodePath owner_path = owner; |
| 396 | + Ref<Resource> owner_res = ResourceLoader::load(owner_path); |
| 397 | + if (Object::cast_to<PackedScene>(owner_res.ptr())) { |
| 398 | + Ref<PackedScene> owner_packed_scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*owner_res)); |
| 399 | + owner_scene_node = owner_packed_scene->instantiate(); |
| 400 | + break; |
| 401 | + } |
| 402 | + } |
| 403 | + |
| 404 | + cache[p_path] = owner_scene_node; |
| 405 | +} |
| 406 | + |
| 407 | +/** |
| 408 | + * Does only one threaded request to the ResourceLoader at a time. |
| 409 | + * Because loading the same subresources in parallel can bring up errors in the editor. |
| 410 | + * */ |
| 411 | +void SceneCache::_add_owner_scene_request(String p_path = "") { |
| 412 | + if (p_path.is_empty()) { |
| 413 | + if (resource_request_queue.size() > 0) { |
| 414 | + p_path = resource_request_queue.front(); |
| 415 | + } else { |
| 416 | + return; |
| 417 | + } |
| 418 | + } |
| 419 | + if (cache.has(p_path) && resource_request_queue.size() == 0) { |
| 420 | + return; |
| 421 | + } |
| 422 | + if (!cache.has(p_path) && !resource_request_queue.has(p_path)) { |
| 423 | + resource_request_queue.push_back(p_path); |
| 424 | + } |
| 425 | + if (is_loading) { |
| 426 | + return; |
| 427 | + } |
| 428 | + |
| 429 | + String path = resource_request_queue.front(); |
| 430 | + if (!owners_path_cache.has(p_path)) { |
| 431 | + _get_owners(EditorFileSystem::get_singleton()->get_filesystem(), path, owners_path_cache[p_path]); |
| 432 | + } |
| 433 | + Error r_error = Error::FAILED; |
| 434 | + while (r_error != Error::OK && owners_path_cache[p_path].size() > 0) { |
| 435 | + NodePath owner_path = owners_path_cache[p_path].front()->get(); |
| 436 | + r_error = ResourceLoader::load_threaded_request(owner_path); |
| 437 | + if (r_error != Error::OK) { |
| 438 | + owners_path_cache[path].pop_front(); |
| 439 | + } |
| 440 | + } |
| 441 | + if (owners_path_cache[path].size() > 0) { |
| 442 | + is_loading = true; |
| 443 | + } else { |
| 444 | + cache[path] = nullptr; |
| 445 | + owners_path_cache.erase(path); |
| 446 | + resource_request_queue.pop_front(); |
| 447 | + _add_owner_scene_request(); |
| 448 | + } |
| 449 | +} |
| 450 | + |
| 451 | +void SceneCache::_check_thread_for_cache_update() { |
| 452 | + if (!is_loading) { |
| 453 | + return; |
| 454 | + } |
| 455 | + |
| 456 | + String check_path = resource_request_queue.front(); |
| 457 | + |
| 458 | + NodePath owner_path = owners_path_cache[check_path].front()->get(); |
| 459 | + |
| 460 | + if (ResourceLoader::load_threaded_get_status(owner_path) != ResourceLoader::ThreadLoadStatus::THREAD_LOAD_LOADED) { |
| 461 | + return; |
| 462 | + } |
| 463 | + |
| 464 | + is_loading = false; |
| 465 | + |
| 466 | + Ref<PackedScene> owner_res = ResourceLoader::load_threaded_get(owner_path); |
| 467 | + if (owner_res.is_valid()) { |
| 468 | + cache[check_path] = owner_res->instantiate(); |
| 469 | + owners_path_cache.erase(check_path); |
| 470 | + resource_request_queue.pop_front(); |
| 471 | + _add_owner_scene_request(); |
| 472 | + return; |
| 473 | + } |
| 474 | + owners_path_cache[check_path].pop_front(); |
| 475 | + if (owners_path_cache[check_path].size() == 0) { |
| 476 | + cache[check_path] = nullptr; |
| 477 | + owners_path_cache.erase(check_path); |
| 478 | + resource_request_queue.pop_front(); |
| 479 | + } |
| 480 | + _add_owner_scene_request(); |
| 481 | +} |
| 482 | + |
| 483 | +bool SceneCache::has(const String &p_path) { |
| 484 | + return cache.has(p_path); |
| 485 | +} |
| 486 | + |
| 487 | +Node *SceneCache::get(const String &p_path) { |
| 488 | + bool remote_use_thread = (bool)_EDITOR_GET("network/language_server/use_thread"); |
| 489 | + if (remote_use_thread) { |
| 490 | + _check_thread_for_cache_update(); |
| 491 | + _add_owner_scene_request(p_path); |
| 492 | + } |
| 493 | + return cache.has(p_path) ? cache[p_path] : nullptr; |
| 494 | +} |
| 495 | + |
| 496 | +Node *SceneCache::get_for_uri(const String &p_uri) { |
| 497 | + String path = workspace->get_file_path(p_uri); |
| 498 | + return get(path); |
| 499 | +} |
| 500 | + |
| 501 | +void SceneCache::set(const String &p_path) { |
| 502 | + bool remote_use_thread = (bool)_EDITOR_GET("network/language_server/use_thread"); |
| 503 | + if (remote_use_thread) { |
| 504 | + _check_thread_for_cache_update(); |
| 505 | + _add_owner_scene_request(p_path); |
| 506 | + } else { |
| 507 | + _set_owner_scene_node(p_path); |
| 508 | + } |
| 509 | +} |
| 510 | + |
| 511 | +void SceneCache::set_for_uri(const String &p_uri) { |
| 512 | + String path = workspace->get_file_path(p_uri); |
| 513 | + set(path); |
| 514 | +} |
| 515 | + |
| 516 | +void SceneCache::erase(const String &p_path) { |
| 517 | + bool remote_use_thread = (bool)_EDITOR_GET("network/language_server/use_thread"); |
| 518 | + if (remote_use_thread && resource_request_queue.has(p_path)) { |
| 519 | + if (is_loading && resource_request_queue.front() == p_path) { |
| 520 | + while (is_loading) { |
| 521 | + _check_thread_for_cache_update(); |
| 522 | + OS::get_singleton()->delay_usec(50000); |
| 523 | + } |
| 524 | + } else { |
| 525 | + resource_request_queue.erase(p_path); |
| 526 | + } |
| 527 | + } |
| 528 | + if (!cache.has(p_path)) { |
| 529 | + return; |
| 530 | + } |
| 531 | + if (cache[p_path]) { |
| 532 | + memdelete(cache[p_path]); |
| 533 | + } |
| 534 | + cache.erase(p_path); |
| 535 | + owners_path_cache.erase(p_path); |
| 536 | +} |
| 537 | + |
| 538 | +void SceneCache::erase_for_uri(const String &p_uri) { |
| 539 | + String path = workspace->get_file_path(p_uri); |
| 540 | + erase(path); |
| 541 | +} |
| 542 | + |
| 543 | +void SceneCache::clear() { |
| 544 | + if (is_loading) { |
| 545 | + while (is_loading) { |
| 546 | + _check_thread_for_cache_update(); |
| 547 | + OS::get_singleton()->delay_usec(100); |
| 548 | + } |
| 549 | + } |
| 550 | + resource_request_queue.clear(); |
| 551 | + for (const KeyValue<String, Node *> &E : cache) { |
| 552 | + if (E.value) { |
| 553 | + memdelete(E.value); |
| 554 | + } |
| 555 | + } |
| 556 | + cache.clear(); |
| 557 | + owners_path_cache.clear(); |
| 558 | + is_loading = false; |
348 | 559 | }
|
0 commit comments