升級了插件的API
This commit is contained in:
parent
5a6ad57705
commit
d56af0f0c6
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=7 format=3 uid="uid://bj2318o3y68x2"]
|
||||
[gd_scene load_steps=15 format=3 uid="uid://bj2318o3y68x2"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://ds6jy3s0hhmwt" path="res://_game/DemoScript.gd" id="1_2tycc"]
|
||||
[ext_resource type="PackedScene" uid="uid://cvqehvdjpoar4" path="res://_player/player_controller.tscn" id="2_gslp7"]
|
||||
|
|
@ -6,13 +6,18 @@
|
|||
[ext_resource type="PackedScene" uid="uid://bt55vmoc83l6g" path="res://_game/scenes/l_1_s_1.tscn" id="4_6jw57"]
|
||||
[ext_resource type="PackedScene" uid="uid://c6and5mqr3wv1" path="res://_game/scenes/l_1_s_2.tscn" id="5_2t6pm"]
|
||||
[ext_resource type="PackedScene" uid="uid://0sivr6aig7gm" path="res://_game/scenes/l_1_s_3.tscn" id="6_xkd7q"]
|
||||
[ext_resource type="Script" uid="uid://5e157vdk6175" path="res://addons/reedscene/scene/ReedScene.gd" id="6_xotud"]
|
||||
[ext_resource type="Script" uid="uid://bh066o84byplh" path="res://addons/reedscene/scene/ReedSceneID.gd" id="7_2tycc"]
|
||||
[ext_resource type="Script" uid="uid://dn0ksjoswquf5" path="res://addons/reedscene/scene/SceneManager.gd" id="8_3ihdv"]
|
||||
[ext_resource type="Script" uid="uid://dsgl7lbyjsiif" path="res://addons/reedscene/act/ActManager.gd" id="9_hc6q0"]
|
||||
[ext_resource type="Script" uid="uid://pxjf5vst08eo" path="res://addons/reedscene/prop/PropManager.gd" id="10_mwuv1"]
|
||||
[ext_resource type="Script" uid="uid://b4menkyub4ce7" path="res://addons/reedscene/prop/PropComponent.gd" id="12_m325v"]
|
||||
[ext_resource type="Script" uid="uid://di41kt2tj34c2" path="res://addons/reedscene/prop/StateManager.gd" id="13_j8v5a"]
|
||||
[ext_resource type="Script" uid="uid://7lml6d1t5xtq" path="res://addons/reedscene/prop/PropState.gd" id="14_acyif"]
|
||||
|
||||
[node name="Game" type="Node2D"]
|
||||
script = ExtResource("1_2tycc")
|
||||
|
||||
[node name="PlayerController" parent="." node_paths=PackedStringArray("auto_controlled_avatar") instance=ExtResource("2_gslp7")]
|
||||
auto_controlled_avatar = NodePath("../Avatar")
|
||||
|
||||
[node name="Avatar" parent="." instance=ExtResource("3_6jw57")]
|
||||
position = Vector2(283, 253)
|
||||
collision_mask = 4
|
||||
|
|
@ -24,3 +29,45 @@ debug_log = true
|
|||
|
||||
[node name="l1_s3" parent="." instance=ExtResource("6_xkd7q")]
|
||||
debug_log = true
|
||||
|
||||
[node name="ReedScene" type="Node2D" parent="."]
|
||||
script = ExtResource("6_xotud")
|
||||
metadata/_custom_type_script = "uid://5e157vdk6175"
|
||||
|
||||
[node name="[Invalid!]" type="Node" parent="ReedScene"]
|
||||
script = ExtResource("7_2tycc")
|
||||
|
||||
[node name="SceneManager" type="Node" parent="ReedScene"]
|
||||
script = ExtResource("8_3ihdv")
|
||||
|
||||
[node name="ActManager" type="Node" parent="ReedScene"]
|
||||
script = ExtResource("9_hc6q0")
|
||||
|
||||
[node name="Props" type="Node2D" parent="ReedScene"]
|
||||
script = ExtResource("10_mwuv1")
|
||||
|
||||
[node name="PlayerController" parent="ReedScene/Props" node_paths=PackedStringArray("auto_controlled_avatar") instance=ExtResource("2_gslp7")]
|
||||
auto_controlled_avatar = NodePath("../../../Avatar")
|
||||
|
||||
[node name="[Prop_0000]" type="Node" parent="ReedScene/Props/PlayerController"]
|
||||
script = ExtResource("12_m325v")
|
||||
prop_id = 0
|
||||
|
||||
[node name="States" type="Node" parent="ReedScene/Props/PlayerController/[Prop_0000]"]
|
||||
script = ExtResource("13_j8v5a")
|
||||
|
||||
[node name="[ID_0] 修改修改修改" type="Node" parent="ReedScene/Props/PlayerController/[Prop_0000]/States"]
|
||||
script = ExtResource("14_acyif")
|
||||
state_id = 0
|
||||
|
||||
[node name="[ID_1] 修改名稱" type="Node" parent="ReedScene/Props/PlayerController/[Prop_0000]/States"]
|
||||
script = ExtResource("14_acyif")
|
||||
state_id = 1
|
||||
|
||||
[node name="[ID_2] 修改名稱3" type="Node" parent="ReedScene/Props/PlayerController/[Prop_0000]/States"]
|
||||
script = ExtResource("14_acyif")
|
||||
state_id = 2
|
||||
|
||||
[node name="[ID_3] 修改名稱4" type="Node" parent="ReedScene/Props/PlayerController/[Prop_0000]/States"]
|
||||
script = ExtResource("14_acyif")
|
||||
state_id = 3
|
||||
|
|
|
|||
|
|
@ -67,9 +67,6 @@ prop_state_map = Dictionary[int, ExtResource("6_fyfyw")]({
|
|||
|
||||
[sub_resource type="Resource" id="Resource_fyfyw"]
|
||||
script = ExtResource("12_fyfyw")
|
||||
child_node_name = null
|
||||
recursive_found = null
|
||||
owned_node_only = null
|
||||
effect_type = 1
|
||||
value = null
|
||||
func_name = &"reset_door_state_id"
|
||||
|
|
@ -78,9 +75,6 @@ metadata/_custom_type_script = "uid://cdvgq0xqdbagk"
|
|||
|
||||
[sub_resource type="Resource" id="Resource_bco80"]
|
||||
script = ExtResource("12_fyfyw")
|
||||
child_node_name = null
|
||||
recursive_found = null
|
||||
owned_node_only = null
|
||||
effect_type = 1
|
||||
value = null
|
||||
func_name = &"door_close"
|
||||
|
|
@ -88,9 +82,6 @@ metadata/_custom_type_script = "uid://cdvgq0xqdbagk"
|
|||
|
||||
[sub_resource type="Resource" id="Resource_22pon"]
|
||||
script = ExtResource("12_fyfyw")
|
||||
child_node_name = null
|
||||
recursive_found = null
|
||||
owned_node_only = null
|
||||
effect_type = 1
|
||||
value = null
|
||||
func_name = &"reset_door_state_id"
|
||||
|
|
@ -99,9 +90,6 @@ metadata/_custom_type_script = "uid://cdvgq0xqdbagk"
|
|||
|
||||
[sub_resource type="Resource" id="Resource_25twt"]
|
||||
script = ExtResource("12_fyfyw")
|
||||
child_node_name = null
|
||||
recursive_found = null
|
||||
owned_node_only = null
|
||||
effect_type = 1
|
||||
value = null
|
||||
func_name = &"door_open"
|
||||
|
|
|
|||
|
|
@ -73,9 +73,6 @@ prop_state_map = Dictionary[int, ExtResource("6_d8y7x")]({
|
|||
|
||||
[sub_resource type="Resource" id="Resource_fyfyw"]
|
||||
script = ExtResource("12_jhhb1")
|
||||
child_node_name = null
|
||||
recursive_found = null
|
||||
owned_node_only = null
|
||||
effect_type = 1
|
||||
value = null
|
||||
func_name = &"reset_door_state_id"
|
||||
|
|
@ -84,9 +81,6 @@ metadata/_custom_type_script = "uid://cdvgq0xqdbagk"
|
|||
|
||||
[sub_resource type="Resource" id="Resource_bco80"]
|
||||
script = ExtResource("12_jhhb1")
|
||||
child_node_name = null
|
||||
recursive_found = null
|
||||
owned_node_only = null
|
||||
effect_type = 1
|
||||
value = null
|
||||
func_name = &"door_close"
|
||||
|
|
@ -94,9 +88,6 @@ metadata/_custom_type_script = "uid://cdvgq0xqdbagk"
|
|||
|
||||
[sub_resource type="Resource" id="Resource_22pon"]
|
||||
script = ExtResource("12_jhhb1")
|
||||
child_node_name = null
|
||||
recursive_found = null
|
||||
owned_node_only = null
|
||||
effect_type = 1
|
||||
value = null
|
||||
func_name = &"reset_door_state_id"
|
||||
|
|
@ -105,9 +96,6 @@ metadata/_custom_type_script = "uid://cdvgq0xqdbagk"
|
|||
|
||||
[sub_resource type="Resource" id="Resource_25twt"]
|
||||
script = ExtResource("12_jhhb1")
|
||||
child_node_name = null
|
||||
recursive_found = null
|
||||
owned_node_only = null
|
||||
effect_type = 1
|
||||
value = null
|
||||
func_name = &"door_open"
|
||||
|
|
|
|||
|
|
@ -1,96 +1,15 @@
|
|||
@tool
|
||||
extends EditorInspectorPlugin
|
||||
|
||||
# ✅ 由 EditorPlugin 注入
|
||||
var editor_interface: EditorInterface
|
||||
const SLOT_SCENE:= preload("res://addons/reedscene/act/StateDrapSlot.tscn")
|
||||
|
||||
func _can_handle(object) -> bool:
|
||||
return object is ActManager
|
||||
|
||||
func _parse_begin(object) -> void:
|
||||
var act_manager := object as ActManager
|
||||
var reed_scene := _get_owner_scene(act_manager)
|
||||
var root := VBoxContainer.new()
|
||||
|
||||
var text := ""
|
||||
text += "Act Table (Debug)\n"
|
||||
text += "Act Count: %d\n" % act_manager.prop_state_map.size()
|
||||
text += "------------------\n"
|
||||
var slot := SLOT_SCENE.instantiate()
|
||||
root.add_child(slot)
|
||||
|
||||
if reed_scene == null:
|
||||
text += "ERROR: ActManager must be a direct child of ReedScene.\n"
|
||||
text += "Current parent: %s\n" % (act_manager.get_parent().name if act_manager.get_parent() else "<null>")
|
||||
|
||||
var label := Label.new()
|
||||
label.text = text
|
||||
label.autowrap_mode = TextServer.AUTOWRAP_WORD
|
||||
add_custom_control(label)
|
||||
return
|
||||
|
||||
var props_root := reed_scene.get_node_or_null(reed_scene.props_root_path)
|
||||
if props_root == null:
|
||||
text += "ERROR: ReedScene Props root not found: %s\n" % str(reed_scene.props_root_path)
|
||||
|
||||
var label2 := Label.new()
|
||||
label2.text = text
|
||||
label2.autowrap_mode = TextServer.AUTOWRAP_WORD
|
||||
add_custom_control(label2)
|
||||
return
|
||||
|
||||
# ✅ 只扫描 Props root 下的 Prop
|
||||
var prop_index := _scan_props_root_for_props(props_root)
|
||||
|
||||
text += "Scene: %s\n" % reed_scene.name
|
||||
text += "Props Root: %s\n" % str(props_root.get_path())
|
||||
text += "Prop Count: %d\n" % prop_index.size()
|
||||
text += "------------------\n"
|
||||
|
||||
for prop_id in prop_index.keys():
|
||||
var info: Dictionary = prop_index[prop_id]
|
||||
text += "PropID: %d | %s\n" % [int(prop_id), str(info["path"])]
|
||||
|
||||
var label := Label.new()
|
||||
label.text = text
|
||||
label.autowrap_mode = TextServer.AUTOWRAP_WORD
|
||||
add_custom_control(label)
|
||||
|
||||
##扫描Prop root
|
||||
func _scan_props_root_for_props(props_root: Node) -> Dictionary:
|
||||
var result := {}
|
||||
|
||||
for prop in props_root.get_children():
|
||||
if not prop is Node:
|
||||
continue
|
||||
|
||||
# PropComponent 必须在 prop 的最上层子节点集中
|
||||
var prop_comp := _find_prop_component_in_top_children(prop)
|
||||
if prop_comp == null:
|
||||
continue
|
||||
|
||||
var pid := prop_comp.prop_id
|
||||
if result.has(pid):
|
||||
var old_info: Dictionary = result[pid]
|
||||
push_warning(
|
||||
"[ActManagerInspector] Duplicate prop_id under Props root: %d\n A: %s\n B: %s"
|
||||
% [pid, str(old_info["path"]), str(prop_comp.get_path())]
|
||||
)
|
||||
else:
|
||||
result[pid] = {
|
||||
"node": prop_comp,
|
||||
"path": prop_comp.get_path()
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
##获取到Prop下的所有的PropComponent
|
||||
func _find_prop_component_in_top_children(prop: Node) -> PropComponent:
|
||||
for child in prop.get_children():
|
||||
if child is PropComponent:
|
||||
return child as PropComponent
|
||||
return null
|
||||
|
||||
##获取到ActManager上方的Scene,应当自查为ReedScene
|
||||
func _get_owner_scene(act_manager: ActManager) -> ReedScene:
|
||||
var p := act_manager.get_parent()
|
||||
if p is ReedScene:
|
||||
return p as ReedScene
|
||||
return null
|
||||
add_custom_control(root)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,130 @@
|
|||
[gd_scene load_steps=4 format=3 uid="uid://bueytdholvmhg"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://ctpxakdux3aej" path="res://addons/reedscene/act/StateDropSlot.gd" id="1_gcu1q"]
|
||||
[ext_resource type="Texture2D" uid="uid://dyxm0rn8hqaa4" path="res://addons/reedscene/act/icon/inform.svg" id="2_lwr2w"]
|
||||
[ext_resource type="Script" uid="uid://4bujoy6crlat" path="res://addons/reedscene/act/StateDropArea.gd" id="2_stte8"]
|
||||
|
||||
[node name="Root" type="PanelContainer"]
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
offset_bottom = 15.0
|
||||
grow_horizontal = 2
|
||||
script = ExtResource("1_gcu1q")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 4
|
||||
theme_override_constants/margin_top = 4
|
||||
theme_override_constants/margin_right = 4
|
||||
theme_override_constants/margin_bottom = 4
|
||||
|
||||
[node name="HBC_Main" type="HBoxContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Index" type="Label" parent="MarginContainer/HBC_Main"]
|
||||
custom_minimum_size = Vector2(24, 0)
|
||||
layout_mode = 2
|
||||
text = "1"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/HBC_Main"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="HBC_Drop" type="HBoxContainer" parent="MarginContainer/HBC_Main/VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 15)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="DropArea" type="PanelContainer" parent="MarginContainer/HBC_Main/VBoxContainer/HBC_Drop"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(30, 30)
|
||||
layout_mode = 2
|
||||
mouse_filter = 1
|
||||
script = ExtResource("2_stte8")
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="MarginContainer/HBC_Main/VBoxContainer/HBC_Drop/DropArea"]
|
||||
modulate = Color(0.7, 0.7, 0.7, 1)
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
texture = ExtResource("2_lwr2w")
|
||||
expand_mode = 1
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/HBC_Main/VBoxContainer/HBC_Drop"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 4
|
||||
theme_override_constants/margin_right = 4
|
||||
|
||||
[node name="StateLabel" type="Label" parent="MarginContainer/HBC_Main/VBoxContainer/HBC_Drop/MarginContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(80, 0)
|
||||
layout_mode = 2
|
||||
text = "Drag state node to icon."
|
||||
|
||||
[node name="HBC_Option" type="HBoxContainer" parent="MarginContainer/HBC_Main/VBoxContainer/HBC_Drop"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 10
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="MarginContainer/HBC_Main/VBoxContainer/HBC_Drop/HBC_Option"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/HBC_Main/VBoxContainer/HBC_Drop/HBC_Option/PanelContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 2
|
||||
theme_override_constants/margin_top = 2
|
||||
theme_override_constants/margin_right = 2
|
||||
theme_override_constants/margin_bottom = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/HBC_Main/VBoxContainer/HBC_Drop/HBC_Option/PanelContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="CB_UseTrans" type="CheckBox" parent="MarginContainer/HBC_Main/VBoxContainer/HBC_Drop/HBC_Option/PanelContainer/MarginContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="MarginContainer/HBC_Main/VBoxContainer/HBC_Drop/HBC_Option/PanelContainer/MarginContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/HBC_Main/VBoxContainer/HBC_Drop/HBC_Option/PanelContainer/MarginContainer/HBoxContainer/PanelContainer"]
|
||||
layout_mode = 2
|
||||
text = "Use Trans"
|
||||
|
||||
[node name="ChooseButton" type="Button" parent="MarginContainer/HBC_Main/VBoxContainer/HBC_Drop/HBC_Option"]
|
||||
layout_mode = 2
|
||||
text = "Choose"
|
||||
|
||||
[node name="ClearButton" type="Button" parent="MarginContainer/HBC_Main/VBoxContainer/HBC_Drop/HBC_Option"]
|
||||
layout_mode = 2
|
||||
text = "Clear"
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/HBC_Main/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 4
|
||||
theme_override_constants/margin_top = 2
|
||||
theme_override_constants/margin_right = 4
|
||||
theme_override_constants/margin_bottom = 2
|
||||
|
||||
[node name="Context" type="RichTextLabel" parent="MarginContainer/HBC_Main/VBoxContainer/MarginContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
bbcode_enabled = true
|
||||
text = "Information will be show here."
|
||||
scroll_active = false
|
||||
|
||||
[node name="VBoxContainer2" type="VBoxContainer" parent="MarginContainer/HBC_Main/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/HBC_Main/VBoxContainer/VBoxContainer2"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="AddButton" type="Button" parent="MarginContainer/HBC_Main/VBoxContainer/VBoxContainer2/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "+"
|
||||
|
||||
[node name="DeleteButton" type="Button" parent="MarginContainer/HBC_Main/VBoxContainer/VBoxContainer2/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "-"
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
@tool
|
||||
extends PanelContainer
|
||||
class_name StateDropArea
|
||||
|
||||
signal node_dropped(node: Node)
|
||||
|
||||
@export var icon_path: NodePath = NodePath("TextureRect")
|
||||
|
||||
const COLOR_IDLE: Color = Color(1, 1, 1, 1.0)
|
||||
const COLOR_CAN_DROP: Color = Color(0.4, 0.7, 1.0, 1.0)
|
||||
const COLOR_CANNOT_DROP: Color = Color(1.0, 0.35, 0.35, 1.0)
|
||||
const COLOR_CHECKED: Color = Color.GREEN
|
||||
|
||||
var _icon: TextureRect
|
||||
var _state := 0 # 0 idle, 1 can, 2 cannot
|
||||
var _current_drag_data: Variant = null
|
||||
|
||||
signal node_path_dropped(node_path: NodePath)
|
||||
|
||||
# =====================================================
|
||||
# Life cycle
|
||||
# =====================================================
|
||||
func _ready() -> void:
|
||||
_icon = get_node_or_null(icon_path) as TextureRect
|
||||
|
||||
mouse_filter = Control.MOUSE_FILTER_PASS
|
||||
_ignore_mouse_recursive(self)
|
||||
|
||||
if _icon:
|
||||
_icon.modulate = COLOR_IDLE
|
||||
|
||||
if custom_minimum_size == Vector2.ZERO:
|
||||
custom_minimum_size = Vector2(32, 32)
|
||||
|
||||
#mouse_entered.connect(_on_mouse_entered)
|
||||
mouse_exited.connect(_on_mouse_exited)
|
||||
|
||||
# =====================================================
|
||||
# Drag & Drop
|
||||
# =====================================================
|
||||
func _can_drop_data(_pos: Vector2, data) -> bool:
|
||||
_current_drag_data = data
|
||||
var r = StateResolveUtils.is_valid_state_drag(data)
|
||||
_set_state(1 if r else 2)
|
||||
return r
|
||||
|
||||
|
||||
func _drop_data(_pos: Vector2, data) -> void:
|
||||
var path := StateResolveUtils.get_state_path_from_drag(data)
|
||||
if path.is_empty():
|
||||
return
|
||||
node_path_dropped.emit(path)
|
||||
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_DRAG_END:
|
||||
_current_drag_data = null
|
||||
_set_state(0)
|
||||
|
||||
|
||||
# =====================================================
|
||||
# Mouse events
|
||||
# =====================================================
|
||||
func _on_mouse_exited() -> void:
|
||||
_set_state(0)
|
||||
|
||||
func _ignore_mouse_recursive(n: Node) -> void:
|
||||
for c in n.get_children():
|
||||
if c is Control:
|
||||
(c as Control).mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_ignore_mouse_recursive(c)
|
||||
|
||||
|
||||
func _set_state(s: int) -> void:
|
||||
if s == _state:
|
||||
return
|
||||
_state = s
|
||||
|
||||
if _icon == null:
|
||||
return
|
||||
|
||||
match _state:
|
||||
0:
|
||||
_icon.modulate = COLOR_IDLE
|
||||
1:
|
||||
_icon.modulate = COLOR_CAN_DROP
|
||||
2:
|
||||
_icon.modulate = COLOR_CANNOT_DROP
|
||||
3:
|
||||
_icon.modulate = COLOR_CHECKED
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://4bujoy6crlat
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
@tool
|
||||
class_name StateDrapSlot
|
||||
extends Control
|
||||
|
||||
@onready var drop_area: StateDropArea = %DropArea
|
||||
@onready var state_label: Label = %StateLabel
|
||||
|
||||
@onready var context: RichTextLabel = %Context
|
||||
|
||||
@onready var cb_use_trans: CheckBox = %CB_UseTrans
|
||||
|
||||
var _cached_single_act: SingleAct = null
|
||||
var _cached_prop_id: int = -1
|
||||
|
||||
const NORMAL_STATE_LABLE: String = "Drag state node to icon."
|
||||
const NORMAL_CONTEXT: String = "Information will be show here."
|
||||
|
||||
const COLOR_IDLE: Color = Color.GRAY
|
||||
const COLOR_CHECKED_1: Color = Color.GREEN
|
||||
const COLOR_CHECKED_2: Color = Color.YELLOW
|
||||
const COLOR_CHECKED_3: Color = Color.ORANGE_RED
|
||||
|
||||
func _ready() -> void:
|
||||
_reset_to_default()
|
||||
_reset_cb_use_trans()
|
||||
|
||||
if drop_area:
|
||||
drop_area.node_path_dropped.connect(_on_node_path_dropped)
|
||||
|
||||
|
||||
func _on_node_path_dropped(path: NodePath) -> void:
|
||||
var state := StateResolveUtils.get_state_node_from_path(path)
|
||||
if state == null:
|
||||
_clear_cached_act()
|
||||
_reset_to_default()
|
||||
return
|
||||
|
||||
var info := StateResolveUtils.resolve_state_display_info(state)
|
||||
if info == null:
|
||||
_clear_cached_act()
|
||||
_reset_to_default()
|
||||
return
|
||||
|
||||
# 创建 / 更新 cached
|
||||
_cached_single_act = SingleAct.new()
|
||||
_cached_single_act.state_id = state.state_id
|
||||
_cached_single_act.use_trans = false
|
||||
_cached_single_act.context = {}
|
||||
|
||||
_cached_prop_id = int(info.prop_id)
|
||||
|
||||
# 启用 CheckBox
|
||||
cb_use_trans.disabled = false
|
||||
cb_use_trans.button_pressed = _cached_single_act.use_trans
|
||||
|
||||
# 直接用 info + cached 刷 UI
|
||||
_set_context(info)
|
||||
|
||||
func _on_use_trans_toggled(pressed: bool) -> void:
|
||||
if _cached_single_act == null:
|
||||
cb_use_trans.button_pressed = false
|
||||
return
|
||||
|
||||
# ✅ 只改 cached
|
||||
_cached_single_act.use_trans = pressed
|
||||
|
||||
# 重新 resolve 一次 info(简单、直观)
|
||||
var state := _resolve_state_from_cached()
|
||||
if state == null:
|
||||
return
|
||||
|
||||
var info := StateResolveUtils.resolve_state_display_info(state)
|
||||
_set_context(info)
|
||||
|
||||
|
||||
func _resolve_state_from_path(path: NodePath) -> ReedPropState:
|
||||
var root := EditorInterface.get_edited_scene_root()
|
||||
if root == null:
|
||||
return null
|
||||
|
||||
var node := root.get_node_or_null(path)
|
||||
if node is ReedPropState:
|
||||
return node
|
||||
|
||||
return null
|
||||
|
||||
## 重置回默认
|
||||
func _reset_to_default() ->void:
|
||||
state_label.text = NORMAL_STATE_LABLE
|
||||
state_label.modulate = COLOR_IDLE
|
||||
|
||||
context.text = NORMAL_CONTEXT
|
||||
context.modulate = COLOR_IDLE
|
||||
|
||||
_reset_cb_use_trans()
|
||||
|
||||
## 初始化use trans 的 check box
|
||||
func _reset_cb_use_trans() ->void:
|
||||
cb_use_trans.disabled = true
|
||||
cb_use_trans.button_pressed = false
|
||||
|
||||
if not cb_use_trans.toggled.is_connected(_on_use_trans_toggled):
|
||||
cb_use_trans.toggled.connect(_on_use_trans_toggled)
|
||||
|
||||
## 初始化启用use trans
|
||||
func _enable_cb_use_trans() -> void:
|
||||
cb_use_trans.disabled = false
|
||||
cb_use_trans.button_pressed = _cached_single_act.use_trans
|
||||
|
||||
|
||||
## 创建一个CachedAct
|
||||
func _build_cached_act(state: ReedPropState, info: Dictionary) -> void:
|
||||
if _cached_single_act == null:
|
||||
_cached_single_act = SingleAct.new()
|
||||
|
||||
_cached_single_act.state_id = state.state_id
|
||||
_cached_single_act.use_trans = false # 默认值,可后续切换
|
||||
_cached_single_act.context = {} # 预留
|
||||
|
||||
# Prop ID 缓存
|
||||
_cached_prop_id = int(info.prop_id)
|
||||
|
||||
## 清空Cached Act
|
||||
func _clear_cached_act() -> void:
|
||||
_cached_single_act = null
|
||||
_cached_prop_id = -1
|
||||
|
||||
## 设置文本
|
||||
func _set_context(info) ->void:
|
||||
if _cached_single_act == null:
|
||||
return
|
||||
|
||||
context.clear()
|
||||
|
||||
# —— 配置颜色变量 —— #
|
||||
var prop_color_str := COLOR_CHECKED_1.to_html(false)
|
||||
var state_color_str := COLOR_CHECKED_1.to_html(false)
|
||||
var id_color_str := COLOR_CHECKED_2.to_html(false)
|
||||
|
||||
var use_trans := _cached_single_act.use_trans
|
||||
var use_mark := "\u2714" if use_trans else "\u2716"
|
||||
var use_mark_color_str := (
|
||||
COLOR_CHECKED_1 if use_trans else COLOR_CHECKED_3
|
||||
).to_html(false)
|
||||
|
||||
var bbcode := ""
|
||||
bbcode += "[table=1][cell]"
|
||||
|
||||
# Prop
|
||||
bbcode += "[b][color=%s]%s[/color][/b] [color=%s](ID_%s)[/color]" % [
|
||||
prop_color_str,
|
||||
info.prop_name,
|
||||
id_color_str,
|
||||
info.prop_id
|
||||
]
|
||||
|
||||
# 空白占位
|
||||
bbcode += "[color=#00000000] [/color]"
|
||||
|
||||
# State
|
||||
bbcode += "[b][color=%s]%s[/color][/b] [color=%s](ID_%s)[/color]" % [
|
||||
state_color_str,
|
||||
info.state_name,
|
||||
id_color_str,
|
||||
info.state_id
|
||||
]
|
||||
|
||||
# 再空白
|
||||
bbcode += "[color=#00000000] [/color]"
|
||||
|
||||
# Use Trans 显示
|
||||
bbcode += "[color=%s]%s[/color] Use Trans" % [
|
||||
use_mark_color_str,
|
||||
use_mark
|
||||
]
|
||||
|
||||
bbcode += "[/cell][/table]"
|
||||
|
||||
context.text = bbcode
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://ctpxakdux3aej
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
'''工具类:用于解析 State / 路径 / 展示信息'''
|
||||
@tool
|
||||
class_name StateResolveUtils
|
||||
|
||||
|
||||
# =====================================================
|
||||
# Section 1: Drag Data → State Path / State Node
|
||||
# =====================================================
|
||||
static func is_valid_state_drag(data) -> bool:
|
||||
return get_state_node_from_drag(data) != null
|
||||
|
||||
|
||||
static func get_state_path_from_drag(data) -> NodePath:
|
||||
var raw := _extract_node_path_from_drag(data)
|
||||
if raw.is_empty():
|
||||
return NodePath()
|
||||
|
||||
return _normalize_to_scene_root(raw)
|
||||
|
||||
|
||||
static func get_state_node_from_drag(data) -> ReedPropState:
|
||||
var path := get_state_path_from_drag(data)
|
||||
if path.is_empty():
|
||||
return null
|
||||
|
||||
return get_state_node_from_path(path)
|
||||
|
||||
|
||||
# =====================================================
|
||||
# Section 2: NodePath → State Node
|
||||
# =====================================================
|
||||
static func get_state_node_from_path(path: NodePath) -> ReedPropState:
|
||||
if path.is_empty():
|
||||
return null
|
||||
|
||||
var root := EditorInterface.get_edited_scene_root()
|
||||
if root == null:
|
||||
return null
|
||||
|
||||
var node := root.get_node_or_null(path)
|
||||
if node is ReedPropState:
|
||||
return node
|
||||
|
||||
return null
|
||||
|
||||
|
||||
# =====================================================
|
||||
# Section 3: State Node → 展示信息
|
||||
# =====================================================
|
||||
|
||||
static func resolve_state_display_info(state: ReedPropState) -> Dictionary:
|
||||
var result := {
|
||||
"prop_name": "",
|
||||
"prop_id": "",
|
||||
"state_name": "",
|
||||
"state_id": ""
|
||||
}
|
||||
|
||||
if state == null:
|
||||
return result
|
||||
|
||||
# --------------------
|
||||
# State 信息
|
||||
# --------------------
|
||||
result.state_name = state.name
|
||||
result.state_id = str(state.state_id)
|
||||
|
||||
# --------------------
|
||||
# PropComponent
|
||||
# --------------------
|
||||
var prop_comp := _find_parent_prop_comp(state)
|
||||
if prop_comp == null:
|
||||
return result
|
||||
|
||||
result.prop_id = str(prop_comp.prop_id)
|
||||
|
||||
# --------------------
|
||||
# Prop 实体节点(PropComponent 的父节点)
|
||||
# --------------------
|
||||
var prop_node := prop_comp.get_parent()
|
||||
if prop_node:
|
||||
result.prop_name = prop_node.name
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# =====================================================
|
||||
# Section 4: Internal helpers
|
||||
# =====================================================
|
||||
|
||||
static func _extract_node_path_from_drag(data) -> NodePath:
|
||||
if typeof(data) != TYPE_DICTIONARY:
|
||||
return NodePath()
|
||||
|
||||
# SceneTree 标准:nodes = [NodePath / String]
|
||||
if data.has("nodes") and data["nodes"] is Array and data["nodes"].size() > 0:
|
||||
var first = data["nodes"][0]
|
||||
if first is NodePath:
|
||||
return first
|
||||
if typeof(first) == TYPE_STRING:
|
||||
return NodePath(first)
|
||||
|
||||
# 少见兜底:直接给了 node
|
||||
if data.has("node") and data["node"] is Node:
|
||||
return (data["node"] as Node).get_path()
|
||||
|
||||
return NodePath()
|
||||
|
||||
|
||||
static func _normalize_to_scene_root(p: NodePath) -> NodePath:
|
||||
if p.is_empty():
|
||||
return p
|
||||
|
||||
var root := EditorInterface.get_edited_scene_root()
|
||||
if root == null:
|
||||
return p
|
||||
|
||||
var root_path := String(root.get_path())
|
||||
var s := String(p)
|
||||
|
||||
# 已经是相对路径
|
||||
if not s.begins_with("/"):
|
||||
return p
|
||||
|
||||
if s.begins_with(root_path):
|
||||
s = s.substr(root_path.length())
|
||||
if s.begins_with("/"):
|
||||
s = s.substr(1)
|
||||
|
||||
return NodePath(s)
|
||||
|
||||
|
||||
static func _find_parent_prop_comp(state: Node) -> PropComponent:
|
||||
var cur := state.get_parent()
|
||||
while cur:
|
||||
if cur is PropComponent:
|
||||
return cur
|
||||
cur = cur.get_parent()
|
||||
return null
|
||||
|
||||
## 通过Path返回ID和State
|
||||
static func resolve_ids_from_state_path(path: NodePath) -> Dictionary:
|
||||
var result := {
|
||||
"prop_id": -1,
|
||||
"state_id": -1
|
||||
}
|
||||
|
||||
var root := EditorInterface.get_edited_scene_root()
|
||||
if root == null:
|
||||
return result
|
||||
|
||||
var node := root.get_node_or_null(path)
|
||||
if not (node is ReedPropState):
|
||||
return result
|
||||
|
||||
result.state_id = node.state_id
|
||||
|
||||
var prop_comp := _find_parent_prop_comp(node)
|
||||
if prop_comp == null:
|
||||
return result
|
||||
|
||||
result.prop_id = prop_comp.prop_id
|
||||
return result
|
||||
|
||||
## 通过id 获取Name
|
||||
static func resolve_names_from_ids(
|
||||
prop_id: int,
|
||||
state_id: int
|
||||
) -> Dictionary:
|
||||
var result := {
|
||||
"prop_name": "",
|
||||
"state_name": ""
|
||||
}
|
||||
|
||||
var root := EditorInterface.get_edited_scene_root()
|
||||
if root == null:
|
||||
return result
|
||||
|
||||
# 遍历 PropComponent(你之后可以优化成表)
|
||||
for prop_comp in root.get_tree().get_nodes_in_group("PropComponent"):
|
||||
if prop_comp.prop_id != prop_id:
|
||||
continue
|
||||
|
||||
var prop_node := prop_comp.get_parent()
|
||||
if prop_node:
|
||||
result.prop_name = prop_node.name
|
||||
|
||||
for child in prop_comp.get_children():
|
||||
if child is ReedPropState and child.state_id == state_id:
|
||||
result.state_name = child.name
|
||||
return result
|
||||
|
||||
return result
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://d1sqnplikvohe
|
||||
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1767424299812" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5075" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M513.024 65.536q93.184 0 175.616 35.84t143.872 97.28 97.28 143.872 35.84 175.616q0 94.208-35.84 176.64t-97.28 143.872-143.872 97.28-175.616 35.84q-94.208 0-176.64-35.84t-143.872-97.28-97.28-143.872-35.84-176.64q0-93.184 35.84-175.616t97.28-143.872 143.872-97.28 176.64-35.84zM513.024 909.312q80.896 0 152.064-30.72t124.416-83.968 83.968-124.416 30.72-152.064-30.72-152.064-83.968-124.416-124.416-83.968-152.064-30.72q-81.92 0-153.088 30.72t-124.416 83.968-83.968 124.416-30.72 152.064 30.72 152.064 83.968 124.416 124.416 83.968 153.088 30.72zM513.024 190.464q66.56 0 124.928 25.088t102.4 69.12 69.12 102.4 25.088 124.928-25.088 125.44-69.12 102.912-102.4 69.12-124.928 25.088-125.44-25.088-102.912-69.12-69.12-102.912-25.088-125.44 25.088-124.928 69.12-102.4 102.912-69.12 125.44-25.088z" p-id="5076" fill="#ffffff"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -0,0 +1,43 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dyxm0rn8hqaa4"
|
||||
path="res://.godot/imported/inform.svg-c5339b427b2c0311215067373a3a7293.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/reedscene/act/icon/inform.svg"
|
||||
dest_files=["res://.godot/imported/inform.svg-c5339b427b2c0311215067373a3a7293.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
|
|
@ -29,7 +29,8 @@ var _states_root: Node
|
|||
var _state_map: Dictionary = {}
|
||||
var _current: ReedPropState = null
|
||||
|
||||
const states_root_name := "States"
|
||||
const STATES_ROOT_NAME := "States"
|
||||
const STATES_ROOT_SCRIPT := preload("res://addons/reedscene/prop/StateManager.gd")
|
||||
const DEFAULT_STATE_ID := 0
|
||||
|
||||
|
||||
|
|
@ -38,19 +39,14 @@ func _enter_tree() -> void:
|
|||
_editor_ensure_states_root()
|
||||
|
||||
func _ready() -> void:
|
||||
if Engine.is_editor_hint():
|
||||
_editor_ready()
|
||||
|
||||
_build_state_cache()
|
||||
|
||||
#if not Engine.is_editor_hint():
|
||||
#if should_wait_owner_ready:
|
||||
#await owner.ready
|
||||
|
||||
#_init_states()
|
||||
|
||||
#if _current == null and initial_state_id >= 0 and overwrite_init_state:
|
||||
#change_state(initial_state_id, false, {
|
||||
#"reason": "INIT",
|
||||
#"instant": true
|
||||
#})
|
||||
## 只在編輯器模式的Ready裏Call的函數
|
||||
func _editor_ready() -> void:
|
||||
child_exiting_tree.connect(_on_child_exiting_tree)
|
||||
|
||||
## 用于初始化状态
|
||||
func init() -> void:
|
||||
|
|
@ -64,17 +60,18 @@ func _init_state_check() ->void:
|
|||
"instant": true
|
||||
})
|
||||
|
||||
##映射State到stateID
|
||||
## 在構造時,映射State到stateID
|
||||
func _build_state_cache() -> void:
|
||||
_state_map.clear()
|
||||
|
||||
_states_root = get_node_or_null(states_root_name)
|
||||
_states_root = get_node_or_null(STATES_ROOT_NAME)
|
||||
if _states_root == null:
|
||||
push_warning("[PropComponent:%s] States root not found" % prop_id)
|
||||
return
|
||||
|
||||
if not _states_root is ReedPropStateManager:
|
||||
push_error("[PropComponent:%s] States root is not ReedPropStateManager" % prop_id)
|
||||
## 判斷子節點是否是StatesRoot節點,此節點的脚本後續會輕量化,所以不設置為一個單獨的類
|
||||
if not _states_root.IS_PROP_STATES_ROOT:
|
||||
push_error("[PropComponent:%s] States root missing PropStatesRoot script" % prop_id)
|
||||
return
|
||||
|
||||
for c in _states_root.get_children():
|
||||
|
|
@ -89,14 +86,6 @@ func _build_state_cache() -> void:
|
|||
if debug_log:
|
||||
print("[PropComponent:%s] States:", _state_map.keys())
|
||||
|
||||
##检查当前是否存在当前Id的State
|
||||
func has_state(state_id: int) -> bool:
|
||||
return _state_map.has(state_id)
|
||||
|
||||
##获取当前的状态ID
|
||||
func get_current_state_id() -> int:
|
||||
return _current.state_id if _current else -1
|
||||
|
||||
##初始化状态
|
||||
func _init_states() -> void:
|
||||
var owner := get_parent()
|
||||
|
|
@ -110,6 +99,99 @@ func _init_states() -> void:
|
|||
push_error("[PropComponent:%s] State init failed: %s"
|
||||
% [prop_id, s.name])
|
||||
|
||||
|
||||
|
||||
## ==============================
|
||||
## Act Sync Entry
|
||||
## ==============================
|
||||
#func sync_to_state(state_id: int, act_id: int, instant := false) -> bool:
|
||||
#var ctx := {
|
||||
#"reason": "ACT_SYNC",
|
||||
#"act_id": act_id,
|
||||
#"instant": instant
|
||||
#}
|
||||
#return change_state(state_id, false ,ctx)
|
||||
|
||||
## ==============================
|
||||
## Editor Tool
|
||||
## ==============================
|
||||
#func _editor_ensure_states_root() -> void:
|
||||
#var states := get_node_or_null(STATES_ROOT_NAME)
|
||||
#if states != null:
|
||||
#return
|
||||
#
|
||||
## 创建 StateManager 而不是普通 Node
|
||||
#states = ReedPropStateManager.new()
|
||||
#states.name = STATES_ROOT_NAME
|
||||
#add_child(states)
|
||||
#
|
||||
## 让其成为 Scene 的一部分(非常重要)
|
||||
#states.owner = get_tree().edited_scene_root
|
||||
#
|
||||
## 自动添加一个默认 State
|
||||
#var default_state := ReedPropState.new()
|
||||
#default_state.name = "Default"
|
||||
#states.add_child(default_state)
|
||||
#default_state.owner = get_tree().edited_scene_root
|
||||
#
|
||||
#if debug_log:
|
||||
#print("[PropComponent] Created States(StateManager) + Default State")
|
||||
|
||||
## 引擎層預知一個工具節點給予到State及其子節點。
|
||||
func _editor_ensure_states_root() -> void:
|
||||
var states := get_node_or_null(STATES_ROOT_NAME)
|
||||
if states:
|
||||
return
|
||||
|
||||
states = Node.new()
|
||||
states.name = STATES_ROOT_NAME
|
||||
states.set_script(STATES_ROOT_SCRIPT)
|
||||
add_child(states)
|
||||
states.owner = get_tree().edited_scene_root
|
||||
|
||||
var default_state := ReedPropState.new()
|
||||
default_state.name = "Default"
|
||||
states.add_child(default_state)
|
||||
default_state.owner = get_tree().edited_scene_root
|
||||
|
||||
## 不允许StatesNode被删除,如果删了会自动补一个
|
||||
func _on_child_exiting_tree(child: Node) -> void:
|
||||
if child.name == STATES_ROOT_NAME:
|
||||
push_error("[PropComponent] 'States' node is required and cannot be removed.")
|
||||
call_deferred("_editor_ensure_states_root")
|
||||
|
||||
## ==============================
|
||||
## External API
|
||||
## ==============================
|
||||
#region 外部接口函数
|
||||
## 使用PropComp獲取PropName,直接返回ParentName
|
||||
func get_prop_name() -> String:
|
||||
return get_parent().name
|
||||
|
||||
## 獲取StatesRoot,返回緩存的StatesRoot
|
||||
func get_states_root() -> Node:
|
||||
return _states_root
|
||||
|
||||
## 通過ID獲取PropState
|
||||
func get_state_by_id(id: int) -> ReedPropState:
|
||||
return _state_map.get(id)
|
||||
|
||||
## 返回State的Size
|
||||
func get_state_size() -> int:
|
||||
return _state_map.keys().size()
|
||||
|
||||
## 返回所有的States
|
||||
func get_all_states() -> Array[ReedPropState]:
|
||||
return _state_map.values()
|
||||
|
||||
##检查是否存在Id的State
|
||||
func has_state(state_id: int) -> bool:
|
||||
return _state_map.has(state_id)
|
||||
|
||||
##获取当前的状态ID
|
||||
func get_current_state_id() -> int:
|
||||
return _current.state_id if _current else -1
|
||||
|
||||
## 切换状态,如果 use_trans 为 true,则会优先检查 next state 下是否存在可用的 Transition
|
||||
func change_state(state_id: int, use_trans: bool, ctx: Dictionary = {}) -> bool:
|
||||
if not _state_map.has(state_id):
|
||||
|
|
@ -165,38 +247,28 @@ func change_state(state_id: int, use_trans: bool, ctx: Dictionary = {}) -> bool:
|
|||
|
||||
return true
|
||||
|
||||
## ==============================
|
||||
## Act Sync Entry
|
||||
## ==============================
|
||||
func sync_to_state(state_id: int, act_id: int, instant := false) -> bool:
|
||||
var ctx := {
|
||||
"reason": "ACT_SYNC",
|
||||
"act_id": act_id,
|
||||
"instant": instant
|
||||
}
|
||||
return change_state(state_id, false ,ctx)
|
||||
## 获取ID的State的Name
|
||||
func get_state_name_by_id(id: int) -> String:
|
||||
var s : ReedPropState = get_state_by_id(id)
|
||||
if not s:
|
||||
return ""
|
||||
return get_state_name(s)
|
||||
|
||||
## ==============================
|
||||
## Editor Tool
|
||||
## ==============================
|
||||
func _editor_ensure_states_root() -> void:
|
||||
var states := get_node_or_null(states_root_name)
|
||||
if states != null:
|
||||
return
|
||||
## 获取State的Name
|
||||
func get_state_name(state: ReedPropState) -> String:
|
||||
if not state:
|
||||
return ""
|
||||
|
||||
# 创建 StateManager 而不是普通 Node
|
||||
states = ReedPropStateManager.new()
|
||||
states.name = states_root_name
|
||||
add_child(states)
|
||||
var n: String = state.name
|
||||
var extract_raw_name := func(name: String) -> String:
|
||||
return (
|
||||
name.substr(name.find("]") + 2)
|
||||
if name.begins_with("[ID:")
|
||||
and name.find("]") != -1
|
||||
and name.find("]") + 2 < name.length()
|
||||
else name
|
||||
)
|
||||
|
||||
# 让其成为 Scene 的一部分(非常重要)
|
||||
states.owner = get_tree().edited_scene_root
|
||||
return extract_raw_name.call(n)
|
||||
|
||||
# 自动添加一个默认 State
|
||||
var default_state := ReedPropState.new()
|
||||
default_state.name = "Default"
|
||||
states.add_child(default_state)
|
||||
default_state.owner = get_tree().edited_scene_root
|
||||
|
||||
if debug_log:
|
||||
print("[PropComponent] Created States(StateManager) + Default State")
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -10,11 +10,12 @@ class_name ReedPropState extends Node
|
|||
##预装的一些Effect,可以用来对State进行一些初始化
|
||||
@export var effects: Array[ReedPropEffect] = []
|
||||
|
||||
const DEFAULT_NAME = "Default"
|
||||
|
||||
##State的拥有者
|
||||
var _owner
|
||||
##State的prop comp
|
||||
var _owner_prop_comp
|
||||
|
||||
## 是否已经初始化
|
||||
var _inited: bool = false
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
'''
|
||||
輔助功能性脚本,可以用來管理所有的PropState,並添加一些幫助性的方法。
|
||||
'''
|
||||
@tool
|
||||
@icon("res://addons/reedscene/prop/icon/prop_states_manager.svg")
|
||||
class_name ReedPropStateManager
|
||||
#class_name ReedPropStateManager
|
||||
extends Node
|
||||
|
||||
## FLAG
|
||||
const IS_PROP_STATES_ROOT := true
|
||||
|
||||
@export var auto_refresh: bool = true
|
||||
|
||||
func _ready() -> void:
|
||||
|
|
@ -11,31 +17,45 @@ func _ready() -> void:
|
|||
|
||||
child_entered_tree.connect(_on_child_entered_tree)
|
||||
child_exiting_tree.connect(_on_child_exiting_tree)
|
||||
child_order_changed.connect(_on_child_order_changing)
|
||||
|
||||
_refresh_states()
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if not Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
if what == NOTIFICATION_CHILD_ORDER_CHANGED:
|
||||
if auto_refresh:
|
||||
call_deferred("_refresh_states")
|
||||
|
||||
## 如果子節點進入管理器
|
||||
func _on_child_entered_tree(node: Node) -> void:
|
||||
if not Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
if not node.renamed.is_connected(_on_child_renamed):
|
||||
node.renamed.connect(_on_child_renamed)
|
||||
|
||||
if node is ReedPropState and auto_refresh:
|
||||
call_deferred("_refresh_states")
|
||||
|
||||
## 如果子節點離開管理器
|
||||
func _on_child_exiting_tree(node: Node) -> void:
|
||||
if not Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
if node.renamed.is_connected(_on_child_renamed):
|
||||
node.renamed.disconnect(_on_child_renamed)
|
||||
|
||||
if node is ReedPropState and auto_refresh:
|
||||
call_deferred("_refresh_states")
|
||||
|
||||
## 如果子節點被重命名
|
||||
func _on_child_renamed() -> void:
|
||||
if not Engine.is_editor_hint():
|
||||
return
|
||||
|
||||
call_deferred("_refresh_states")
|
||||
|
||||
## 如果子節點的順序修改
|
||||
func _on_child_order_changing() -> void:
|
||||
if not Engine.is_editor_hint():
|
||||
return
|
||||
call_deferred("_refresh_states")
|
||||
|
||||
func _refresh_states() -> void:
|
||||
var index := 0
|
||||
|
||||
|
|
@ -62,6 +82,7 @@ func _rename_state_node(state: ReedPropState, id: int) -> void:
|
|||
|
||||
state.name = expected
|
||||
|
||||
##连续剥离Name,防止错乱
|
||||
func _strip_id_prefix(name: String) -> String:
|
||||
var result := name
|
||||
|
||||
|
|
@ -80,6 +101,7 @@ func _strip_id_prefix(name: String) -> String:
|
|||
|
||||
return result.strip_edges()
|
||||
|
||||
## 提取原本的命名
|
||||
func _extract_raw_name(name: String) -> String:
|
||||
if name.begins_with("[ID:"):
|
||||
var end := name.find("]")
|
||||
|
|
|
|||
|
|
@ -3,68 +3,117 @@ extends EditorPlugin
|
|||
|
||||
var inspector_plugins: Array[EditorInspectorPlugin] = []
|
||||
|
||||
const AUTOLOAD_REED_SCENE_NAME: StringName = "ReedSceneRegistry"
|
||||
const AUTOLOAD_REED_SCENE_PATH:= "res://addons/reedscene/scene/SceneRegistry.gd"
|
||||
const AUTOLOAD_REED_SCENE_NAME: StringName = &"ReedSceneRegistry"
|
||||
const AUTOLOAD_REED_SCENE_PATH := "res://addons/reedscene/scene/SceneRegistry.gd"
|
||||
|
||||
var toolbar_button: Button
|
||||
var main_screen: Control
|
||||
|
||||
|
||||
# ======================================================
|
||||
# 生命周期
|
||||
# ======================================================
|
||||
|
||||
func _enter_tree() -> void:
|
||||
_load_mainscreen()
|
||||
_ensure_autoload()
|
||||
_register_inspectors()
|
||||
|
||||
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:
|
||||
_unload_mainscreen()
|
||||
_remove_autoload()
|
||||
_unregister_inspectors()
|
||||
|
||||
##自动删除单例
|
||||
if ProjectSettings.has_setting("autoload/%s" % AUTOLOAD_REED_SCENE_NAME):
|
||||
remove_autoload_singleton(AUTOLOAD_REED_SCENE_NAME)
|
||||
|
||||
# 移除 InspectorPlugin
|
||||
# ======================================================
|
||||
# Inspector Plugins
|
||||
# ======================================================
|
||||
func _register_inspectors() -> void:
|
||||
# Inspector 1:ActManager
|
||||
var act_inspector := preload(
|
||||
"res://addons/reedscene/act/ActManagerInspector.gd"
|
||||
).new()
|
||||
|
||||
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 _unregister_inspectors() -> void:
|
||||
for plugin in inspector_plugins:
|
||||
remove_inspector_plugin(plugin)
|
||||
inspector_plugins.clear()
|
||||
|
||||
##加載主界面
|
||||
|
||||
# ======================================================
|
||||
# Autoload
|
||||
# ======================================================
|
||||
|
||||
func _ensure_autoload() -> void:
|
||||
var key := "autoload/%s" % AUTOLOAD_REED_SCENE_NAME
|
||||
if not ProjectSettings.has_setting(key):
|
||||
add_autoload_singleton(
|
||||
AUTOLOAD_REED_SCENE_NAME,
|
||||
AUTOLOAD_REED_SCENE_PATH
|
||||
)
|
||||
|
||||
|
||||
func _remove_autoload() -> void:
|
||||
var key := "autoload/%s" % AUTOLOAD_REED_SCENE_NAME
|
||||
if ProjectSettings.has_setting(key):
|
||||
remove_autoload_singleton(AUTOLOAD_REED_SCENE_NAME)
|
||||
|
||||
|
||||
# ======================================================
|
||||
# Main Screen
|
||||
# ======================================================
|
||||
|
||||
func _load_mainscreen() -> void:
|
||||
main_screen = preload("res://addons/reedscene/dock/SceneIDMainPanel.tscn").instantiate()
|
||||
main_screen = preload(
|
||||
"res://addons/reedscene/dock/SceneIDMainPanel.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 not main_screen: return
|
||||
if not main_screen:
|
||||
return
|
||||
|
||||
main_screen.visible = visible
|
||||
if visible:
|
||||
main_screen.on_activated()
|
||||
|
||||
if visible and main_screen.has_method("on_activated"):
|
||||
main_screen.on_activated()
|
||||
|
||||
|
||||
# ======================================================
|
||||
# Meta
|
||||
# ======================================================
|
||||
|
||||
func _get_plugin_name() -> String:
|
||||
return "Reed Scene"
|
||||
|
||||
|
||||
func _get_plugin_icon() -> Texture2D:
|
||||
return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons")
|
||||
return EditorInterface.get_editor_theme().get_icon(
|
||||
"Node",
|
||||
"EditorIcons"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ V1.0
|
|||
- Scene管理器全局ID功能
|
||||
|
||||
V1.1
|
||||
|
||||
- 添加和规范API
|
||||
- 删除不必要的ClassName
|
||||
- 完善ActManager的编辑者友好界面
|
||||
|
|
|
|||
Loading…
Reference in New Issue