From bc848b85268403c2fb28477f6ec9211fcbbb797d Mon Sep 17 00:00:00 2001 From: Reed Date: Thu, 1 Jan 2026 16:33:32 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=8F=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _game/LevelDemonstration.tscn | 12 +- .../demo/data_base/GLOBAL_SCENE_ID.tres | 10 ++ addons/reedscene/dock/scene_id_main_screen.gd | 27 +++++ .../dock/scene_id_main_screen.gd.uid | 1 + .../reedscene/dock/scene_id_main_screen.tscn | 17 +++ addons/reedscene/reedscene.gd | 69 ++++++++++-- addons/reedscene/scene/ReedSceneID.gd | 8 ++ addons/reedscene/scene/ReedSceneID.gd.uid | 1 + .../scene/ReedSceneIDEditorSystem.gd | 39 +++++++ .../scene/ReedSceneIDEditorSystem.gd.uid | 1 + .../reedscene/scene/ReedSceneIDInspector.gd | 31 ++++++ .../scene/ReedSceneIDInspector.gd.uid | 1 + addons/reedscene/scene/SceneIDDatabase.gd | 7 ++ addons/reedscene/scene/SceneIDDatabase.gd.uid | 1 + addons/reedscene/scene/SceneRegistry.gd | 103 ++++++++++++++++++ addons/reedscene/scene/SceneRegistry.gd.uid | 1 + project.godot | 1 + 17 files changed, 320 insertions(+), 10 deletions(-) create mode 100644 addons/reedscene/demo/data_base/GLOBAL_SCENE_ID.tres create mode 100644 addons/reedscene/dock/scene_id_main_screen.gd create mode 100644 addons/reedscene/dock/scene_id_main_screen.gd.uid create mode 100644 addons/reedscene/dock/scene_id_main_screen.tscn create mode 100644 addons/reedscene/scene/ReedSceneID.gd create mode 100644 addons/reedscene/scene/ReedSceneID.gd.uid create mode 100644 addons/reedscene/scene/ReedSceneIDEditorSystem.gd create mode 100644 addons/reedscene/scene/ReedSceneIDEditorSystem.gd.uid create mode 100644 addons/reedscene/scene/ReedSceneIDInspector.gd create mode 100644 addons/reedscene/scene/ReedSceneIDInspector.gd.uid create mode 100644 addons/reedscene/scene/SceneIDDatabase.gd create mode 100644 addons/reedscene/scene/SceneIDDatabase.gd.uid create mode 100644 addons/reedscene/scene/SceneRegistry.gd create mode 100644 addons/reedscene/scene/SceneRegistry.gd.uid diff --git a/_game/LevelDemonstration.tscn b/_game/LevelDemonstration.tscn index 08d4d46..13b44f2 100644 --- a/_game/LevelDemonstration.tscn +++ b/_game/LevelDemonstration.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=39 format=4 uid="uid://bj2318o3y68x2"] +[gd_scene load_steps=40 format=4 uid="uid://bj2318o3y68x2"] [ext_resource type="Script" uid="uid://ds6jy3s0hhmwt" path="res://_game/DemoScript.gd" id="1_2tycc"] [ext_resource type="PackedScene" uid="uid://1l06de041i40" path="res://_levels/l_level_1.tscn" id="1_p0ota"] @@ -7,6 +7,7 @@ [ext_resource type="PackedScene" uid="uid://b5nx4dntm0gyn" path="res://_props/door_manager/event_trigger_door.tscn" id="4_p0ota"] [ext_resource type="Script" uid="uid://b4menkyub4ce7" path="res://addons/reedscene/prop/PropComponent.gd" id="5_gslp7"] [ext_resource type="Script" uid="uid://7lml6d1t5xtq" path="res://addons/reedscene/prop/PropState.gd" id="6_6jw57"] +[ext_resource type="Script" uid="uid://bh066o84byplh" path="res://addons/reedscene/scene/ReedSceneID.gd" id="6_hc6q0"] [ext_resource type="Script" uid="uid://cdvgq0xqdbagk" path="res://addons/reedscene/prop/ReedPropEffect.gd" id="7_2t6pm"] [ext_resource type="Script" uid="uid://fxpk2ot6otfh" path="res://addons/reedscene/act/Act.gd" id="7_xotud"] [ext_resource type="Script" uid="uid://baqgorvlumyju" path="res://addons/reedscene/act/SingleAct.gd" id="8_2tycc"] @@ -50,12 +51,12 @@ script = ExtResource("8_2tycc") state_id = 1 metadata/_custom_type_script = "uid://baqgorvlumyju" -[sub_resource type="Resource" id="Resource_xiw5v"] +[sub_resource type="Resource" id="Resource_cqglw"] script = ExtResource("8_2tycc") state_id = 1 metadata/_custom_type_script = "uid://baqgorvlumyju" -[sub_resource type="Resource" id="Resource_cqglw"] +[sub_resource type="Resource" id="Resource_xiw5v"] script = ExtResource("8_2tycc") state_id = 1 metadata/_custom_type_script = "uid://baqgorvlumyju" @@ -164,6 +165,11 @@ collision_mask = 4 script = ExtResource("13_2tycc") metadata/_custom_type_script = "uid://5e157vdk6175" +[node name="ReedSceneID" type="Node" parent="ReedScene"] +script = ExtResource("6_hc6q0") +scene_id = 10000 +metadata/_custom_type_script = "uid://bh066o84byplh" + [node name="SceneManager" type="Node" parent="ReedScene" node_paths=PackedStringArray("TransitionNode")] script = ExtResource("15_hc6q0") TransitionNode = NodePath("Transition") diff --git a/addons/reedscene/demo/data_base/GLOBAL_SCENE_ID.tres b/addons/reedscene/demo/data_base/GLOBAL_SCENE_ID.tres new file mode 100644 index 0000000..50716cc --- /dev/null +++ b/addons/reedscene/demo/data_base/GLOBAL_SCENE_ID.tres @@ -0,0 +1,10 @@ +[gd_resource type="Resource" script_class="SceneIDDatabase" load_steps=2 format=3 uid="uid://4c26uejocdos"] + +[ext_resource type="Script" uid="uid://delj6tsrxv8s3" path="res://addons/reedscene/scene/SceneIDDatabase.gd" id="1_47k6c"] + +[resource] +script = ExtResource("1_47k6c") +next_id = 10001 +scene_map = { +"res://_game/LevelDemonstration.tscn": 10000 +} diff --git a/addons/reedscene/dock/scene_id_main_screen.gd b/addons/reedscene/dock/scene_id_main_screen.gd new file mode 100644 index 0000000..a2db9ce --- /dev/null +++ b/addons/reedscene/dock/scene_id_main_screen.gd @@ -0,0 +1,27 @@ +@tool +extends Control + +@onready var tree: Tree = %Tree + +func _ready(): + _setup_tree() + _fill_dummy_data() + +func _setup_tree(): + tree.clear() + tree.columns = 3 + tree.set_column_title(0, "ID") + tree.set_column_title(1, "Scene Path") + tree.set_column_title(2, "Action") + +func _fill_dummy_data(): + var root := tree.create_item() + + _add_row(root, 10001, "res://levels/level_1.tscn") + _add_row(root, 10002, "res://levels/level_2.tscn") + +func _add_row(root: TreeItem, id: int, path: String): + var item := tree.create_item(root) + item.set_text(0, str(id)) + item.set_text(1, path) + item.set_text(2, "Open") diff --git a/addons/reedscene/dock/scene_id_main_screen.gd.uid b/addons/reedscene/dock/scene_id_main_screen.gd.uid new file mode 100644 index 0000000..de1b094 --- /dev/null +++ b/addons/reedscene/dock/scene_id_main_screen.gd.uid @@ -0,0 +1 @@ +uid://bi8dmt4ypmbhq diff --git a/addons/reedscene/dock/scene_id_main_screen.tscn b/addons/reedscene/dock/scene_id_main_screen.tscn new file mode 100644 index 0000000..8f6ca8a --- /dev/null +++ b/addons/reedscene/dock/scene_id_main_screen.tscn @@ -0,0 +1,17 @@ +[gd_scene load_steps=2 format=3 uid="uid://detpkhtovi6bp"] + +[ext_resource type="Script" uid="uid://bi8dmt4ypmbhq" path="res://addons/reedscene/dock/scene_id_main_screen.gd" id="1_jm7r3"] + +[node name="SceneIdMainScreen" type="CenterContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_jm7r3") + +[node name="Tree" type="Tree" parent="."] +unique_name_in_owner = true +layout_mode = 2 +columns = 3 +hide_root = true diff --git a/addons/reedscene/reedscene.gd b/addons/reedscene/reedscene.gd index ee49086..b3081cf 100644 --- a/addons/reedscene/reedscene.gd +++ b/addons/reedscene/reedscene.gd @@ -1,14 +1,69 @@ @tool extends EditorPlugin -var inspector_plugin +var inspector_plugins: Array[EditorInspectorPlugin] = [] + +const AUTOLOAD_REED_SCENE_NAME: StringName = "ReedSceneSystem" +const AUTOLOAD_REED_SCENE_PATH:= "res://addons/reedscene/scene/SceneRegistry.gd" + +var toolbar_button: Button +var scene_id_window: Window +var main_screen: Control func _enter_tree() -> void: - inspector_plugin = preload("res://addons/reedscene/act/ActManagerInspector.gd").new() - # ✅ 注入 EditorInterface - inspector_plugin.editor_interface = get_editor_interface() - add_inspector_plugin(inspector_plugin) + _load_mainscreen() + + if not ProjectSettings.has_setting("autoload/%s" % AUTOLOAD_REED_SCENE_NAME): + add_autoload_singleton(AUTOLOAD_REED_SCENE_NAME, AUTOLOAD_REED_SCENE_PATH) + + # Inspector 1:你已有的 + var act_inspector := preload( + "res://addons/reedscene/act/ActManagerInspector.gd" + ).new() + act_inspector.editor_interface = get_editor_interface() + add_inspector_plugin(act_inspector) + inspector_plugins.append(act_inspector) + + # Inspector 2:新的(比如 ReedSceneID) + var scene_id_inspector := preload( + "res://addons/reedscene/scene/ReedSceneIDInspector.gd" + ).new() + add_inspector_plugin(scene_id_inspector) + inspector_plugins.append(scene_id_inspector) func _exit_tree() -> void: - if inspector_plugin: - remove_inspector_plugin(inspector_plugin) + _unload_mainscreen() + + ##自动删除单例 + if ProjectSettings.has_setting("autoload/%s" % AUTOLOAD_REED_SCENE_NAME): + remove_autoload_singleton(AUTOLOAD_REED_SCENE_NAME) + + # 移除 InspectorPlugin + for plugin in inspector_plugins: + remove_inspector_plugin(plugin) + inspector_plugins.clear() + +##加載主界面 +func _load_mainscreen() -> void: + main_screen = preload("res://addons/reedscene/dock/scene_id_main_screen.tscn").instantiate() + EditorInterface.get_editor_main_screen().add_child(main_screen) + main_screen.visible = false + +##卸載主界面 +func _unload_mainscreen() -> void: + if main_screen: + main_screen.queue_free() + main_screen = null + +func _has_main_screen() -> bool: + return true + +func _make_visible(visible: bool) -> void: + if main_screen: + main_screen.visible = visible + +func _get_plugin_name() -> String: + return "Reed Scene" + +func _get_plugin_icon() -> Texture2D: + return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons") diff --git a/addons/reedscene/scene/ReedSceneID.gd b/addons/reedscene/scene/ReedSceneID.gd new file mode 100644 index 0000000..54631a7 --- /dev/null +++ b/addons/reedscene/scene/ReedSceneID.gd @@ -0,0 +1,8 @@ +@tool +extends Node +class_name ReedSceneID + +@export var scene_id: int = -1 + +func has_id() -> bool: + return scene_id >= 0 diff --git a/addons/reedscene/scene/ReedSceneID.gd.uid b/addons/reedscene/scene/ReedSceneID.gd.uid new file mode 100644 index 0000000..10fbf3a --- /dev/null +++ b/addons/reedscene/scene/ReedSceneID.gd.uid @@ -0,0 +1 @@ +uid://bh066o84byplh diff --git a/addons/reedscene/scene/ReedSceneIDEditorSystem.gd b/addons/reedscene/scene/ReedSceneIDEditorSystem.gd new file mode 100644 index 0000000..1615752 --- /dev/null +++ b/addons/reedscene/scene/ReedSceneIDEditorSystem.gd @@ -0,0 +1,39 @@ +@tool +extends RefCounted +class_name ReedSceneIDEditorSystem + +const DB_PATH := "res://addons/reedscene/demo/data_base/GLOBAL_SCENE_ID.tres" + +static func _load_db_readonly() -> SceneIDDatabase: + # 忽略缓存,避免拿到同一个共享实例(更稳) + return ResourceLoader.load(DB_PATH, "", ResourceLoader.CACHE_MODE_IGNORE) + +static func _clone_db_to_new(db_ro: SceneIDDatabase) -> SceneIDDatabase: + var db := SceneIDDatabase.new() + if db_ro: + db.next_id = db_ro.next_id + # 深拷贝 Dictionary,彻底断开只读引用链 + db.scene_map = db_ro.scene_map.duplicate(true) + return db + +static func request_id_for_scene(scene_path: String) -> int: + var db_ro := _load_db_readonly() + if db_ro == null: + push_error("[ReedSceneIDEditorSystem] Database not found: " + DB_PATH) + return -1 + + var db := _clone_db_to_new(db_ro) + + if db.scene_map.has(scene_path): + return int(db.scene_map[scene_path]) + + var new_id := db.next_id + db.next_id += 1 + db.scene_map[scene_path] = new_id + + var err := ResourceSaver.save(db, DB_PATH) + if err != OK: + push_error("[ReedSceneIDEditorSystem] Failed to save DB (%s), err=%d" % [DB_PATH, err]) + return -1 + + return new_id diff --git a/addons/reedscene/scene/ReedSceneIDEditorSystem.gd.uid b/addons/reedscene/scene/ReedSceneIDEditorSystem.gd.uid new file mode 100644 index 0000000..58bd511 --- /dev/null +++ b/addons/reedscene/scene/ReedSceneIDEditorSystem.gd.uid @@ -0,0 +1 @@ +uid://b86r8tai4kygo diff --git a/addons/reedscene/scene/ReedSceneIDInspector.gd b/addons/reedscene/scene/ReedSceneIDInspector.gd new file mode 100644 index 0000000..e756489 --- /dev/null +++ b/addons/reedscene/scene/ReedSceneIDInspector.gd @@ -0,0 +1,31 @@ +@tool +extends EditorInspectorPlugin + +func _can_handle(object) -> bool: + return object is ReedSceneID + +func _parse_begin(object): + var button := Button.new() + button.text = "Request Scene ID" + button.pressed.connect(func(): + _request_id(object) + ) + add_custom_control(button) + +func _request_id(id_comp: ReedSceneID): + var scene := id_comp.get_owner() + if scene == null: + push_error("[ReedSceneID] Cannot find owning scene") + return + + var scene_path := scene.scene_file_path + if scene_path == "": + push_error("[ReedSceneID] Scene must be saved before requesting ID") + return + + var id := ReedSceneIDEditorSystem.request_id_for_scene(scene_path) + if id < 0: + return + + id_comp.scene_id = id + id_comp.notify_property_list_changed() diff --git a/addons/reedscene/scene/ReedSceneIDInspector.gd.uid b/addons/reedscene/scene/ReedSceneIDInspector.gd.uid new file mode 100644 index 0000000..2e9dfe2 --- /dev/null +++ b/addons/reedscene/scene/ReedSceneIDInspector.gd.uid @@ -0,0 +1 @@ +uid://h6liq147is5g diff --git a/addons/reedscene/scene/SceneIDDatabase.gd b/addons/reedscene/scene/SceneIDDatabase.gd new file mode 100644 index 0000000..7b18885 --- /dev/null +++ b/addons/reedscene/scene/SceneIDDatabase.gd @@ -0,0 +1,7 @@ +extends Resource +class_name SceneIDDatabase + +@export var next_id: int = 10000 + +# scene_path (String) -> scene_id (int) +@export var scene_map: Dictionary = {} diff --git a/addons/reedscene/scene/SceneIDDatabase.gd.uid b/addons/reedscene/scene/SceneIDDatabase.gd.uid new file mode 100644 index 0000000..8dd7be1 --- /dev/null +++ b/addons/reedscene/scene/SceneIDDatabase.gd.uid @@ -0,0 +1 @@ +uid://delj6tsrxv8s3 diff --git a/addons/reedscene/scene/SceneRegistry.gd b/addons/reedscene/scene/SceneRegistry.gd new file mode 100644 index 0000000..c8665e4 --- /dev/null +++ b/addons/reedscene/scene/SceneRegistry.gd @@ -0,0 +1,103 @@ +# id (int) -> WeakRef(ReedScene) +var _by_id: Dictionary = {} + +signal registered(id: int, node: ReedScene) +signal unregistered(id: int) +signal conflict(id: int, existing: ReedScene, incoming: ReedScene) + +# ------------------------- +# 注册 +# ------------------------- +func register(id: int, node: ReedScene) -> bool: + if id < 0: + push_error("[SceneRegistry] register(): invalid id (<0): %d" % id) + return false + + if node == null: + push_error("[SceneRegistry] register(): node is null for id=%d" % id) + return false + + _cleanup_dead(id) + + if _by_id.has(id): + var existing: ReedScene = _by_id[id].get_ref() + if existing == node: + return true # 重复注册同一个实例,忽略 + + emit_signal("conflict", id, existing, node) + push_error( + "[SceneRegistry] Duplicate id=%d existing=%s incoming=%s" + % [id, existing, node] + ) + return false + + _by_id[id] = weakref(node) + emit_signal("registered", id, node) + return true + +# ------------------------- +# 注销 +# ------------------------- +func unregister(id: int, node: ReedScene = null) -> void: + if not _by_id.has(id): + return + + var existing: ReedScene = _by_id[id].get_ref() + if node != null and existing != node: + # 防止误删 + return + + _by_id.erase(id) + emit_signal("unregistered", id) + +# ------------------------- +# 查询 +# ------------------------- +func get_scene(id: int) -> ReedScene: + _cleanup_dead(id) + var ref: WeakRef = _by_id.get(id) + return ref.get_ref() if ref else null + +func has(id: int) -> bool: + return get_scene(id) != null + +# ------------------------- +# 调用 +# ------------------------- +func call_scene(id: int, method: String, args: Array = []) -> Variant: + var n := get_scene(id) + if n == null: + push_warning("[SceneRegistry] call_scene(): id not found: %d" % id) + return null + + if not n.has_method(method): + push_warning( + "[SceneRegistry] call_scene(): id=%d has no method '%s'" + % [id, method] + ) + return null + + return n.callv(method, args) + +# ------------------------- +# 列表 +# ------------------------- +func list_ids() -> PackedInt32Array: + for id in _by_id.keys(): + _cleanup_dead(id) + + var result := PackedInt32Array() + for id in _by_id.keys(): + result.append(id) + return result + +# ------------------------- +# 内部:清理死引用 +# ------------------------- +func _cleanup_dead(id: int) -> void: + if not _by_id.has(id): + return + + var ref: WeakRef = _by_id[id] + if ref == null or ref.get_ref() == null: + _by_id.erase(id) diff --git a/addons/reedscene/scene/SceneRegistry.gd.uid b/addons/reedscene/scene/SceneRegistry.gd.uid new file mode 100644 index 0000000..2a42bb0 --- /dev/null +++ b/addons/reedscene/scene/SceneRegistry.gd.uid @@ -0,0 +1 @@ +uid://iau86ajv4jv diff --git a/project.godot b/project.godot index aa9da25..6075ba3 100644 --- a/project.godot +++ b/project.godot @@ -22,6 +22,7 @@ CameraSystem="*res://_shared/CameraSystem.tscn" RoomSystem="*res://_shared/room_system.gd" GlobalEvent="*res://_shared/global_event.gd" ReedVFX="*res://addons/reedfx/vfx/ReedVFXSystem.tscn" +ReedSceneSystem="*res://addons/reedscene/scene/SceneRegistry.gd" [display]