└── addons └── eazy_dialog ├── main.gd.uid ├── plugin.gd.uid ├── main_view.gd.uid ├── components ├── item.gd.uid ├── Compiler.cs.uid ├── Resolver.cs.uid ├── muti_node.gd.uid ├── EazyDialogRuntime.cs.uid ├── editor │ ├── dialog_edit.gd.uid │ ├── dialog_edit.gd │ └── dialog_edit.tscn ├── compiler.tscn ├── item.gd ├── muti_node.gd ├── dialog_context.tscn ├── end_node.tscn ├── start_node.tscn ├── item_dialog.tscn ├── dialog_node.tscn ├── muti_node.tscn ├── EazyDialogRuntime.cs ├── Resolver.cs └── Compiler.cs ├── eazy_dialog_runtime.gd.uid ├── plugin.cfg ├── node_style.tres ├── icon ├── file.svg ├── add_character.svg ├── add.svg ├── save.svg ├── delete.svg ├── dialog_text.svg └── dialog.svg ├── plugin.gd ├── eazy_dialog_runtime.gd ├── main.gd ├── main_view.gd ├── eazy_dialog.tscn16798228990.tmp └── main.tscn /addons/eazy_dialog/main.gd.uid: -------------------------------------------------------------------------------- 1 | uid://ctgr1vtlph2kk 2 | -------------------------------------------------------------------------------- /addons/eazy_dialog/plugin.gd.uid: -------------------------------------------------------------------------------- 1 | uid://2w0rnn1rd4rf 2 | -------------------------------------------------------------------------------- /addons/eazy_dialog/main_view.gd.uid: -------------------------------------------------------------------------------- 1 | uid://bgaq00g2th64d 2 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/item.gd.uid: -------------------------------------------------------------------------------- 1 | uid://bj6jmv62yd5kf 2 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/Compiler.cs.uid: -------------------------------------------------------------------------------- 1 | uid://dmssf6jsnbt3y 2 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/Resolver.cs.uid: -------------------------------------------------------------------------------- 1 | uid://b7ksxlca2qwp6 2 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/muti_node.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cs5vg5fxtrcjb 2 | -------------------------------------------------------------------------------- /addons/eazy_dialog/eazy_dialog_runtime.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cwdxb0mrcwsqf 2 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/EazyDialogRuntime.cs.uid: -------------------------------------------------------------------------------- 1 | uid://b38gib0imotd6 2 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/editor/dialog_edit.gd.uid: -------------------------------------------------------------------------------- 1 | uid://b5slpjeiuqkgl 2 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/compiler.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene format=3 uid="uid://dl2h84k6j5rrm"] 2 | 3 | [node name="Compiler" type="Node"] 4 | -------------------------------------------------------------------------------- /addons/eazy_dialog/plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="Eazy Dialog" 4 | description="Eazy Dialog" 5 | author="Ivan" 6 | version="0.2.5" 7 | script="plugin.gd" 8 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/item.gd: -------------------------------------------------------------------------------- 1 | 2 | @tool 3 | extends HBoxContainer 4 | 5 | 6 | 7 | func _on_button_pressed() -> void: 8 | get_parent().remove_child(self) 9 | -------------------------------------------------------------------------------- /addons/eazy_dialog/node_style.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Theme" load_steps=2 format=3 uid="uid://dialggjrx4vmt"] 2 | 3 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_hvsfu"] 4 | content_margin_left = 8.0 5 | bg_color = Color(0.0509804, 0.431373, 0.992157, 1) 6 | corner_radius_top_left = 8 7 | corner_radius_top_right = 8 8 | 9 | [resource] 10 | GraphNode/styles/titlebar = SubResource("StyleBoxFlat_hvsfu") 11 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/muti_node.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends GraphNode 3 | const ITEM_DIALOG = preload("res://addons/eazy_dialog/components/item_dialog.tscn") 4 | @onready var item_container: VBoxContainer = $VBoxContainer/ItemContainer 5 | var index = 0 6 | func _on_add_item_button_pressed() -> void: 7 | var item = ITEM_DIALOG.instantiate() 8 | item.name = "item_"+str(index) 9 | item_container.add_child(item) 10 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/editor/dialog_edit.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | 3 | extends GraphEdit 4 | 5 | func _on_connection_request(from_node: StringName, from_port: int, to_node: StringName, to_port: int) -> void: 6 | connect_node(from_node,from_port,to_node,to_port) 7 | 8 | 9 | func _on_delete_nodes_request(nodes: Array[StringName]) -> void: 10 | for node_name in nodes: 11 | var node = get_node_or_null(node_name.simplify_path()) 12 | if node: 13 | remove_child(node) 14 | -------------------------------------------------------------------------------- /addons/eazy_dialog/icon/file.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/dialog_context.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene format=3 uid="uid://dndw6nbqmg1ms"] 2 | 3 | [node name="PanelContainer" type="PanelContainer"] 4 | offset_top = 203.0 5 | offset_right = 276.0 6 | offset_bottom = 391.0 7 | size_flags_horizontal = 3 8 | size_flags_vertical = 3 9 | 10 | [node name="VBoxContainer" type="VBoxContainer" parent="."] 11 | layout_mode = 2 12 | 13 | [node name="Label" type="Label" parent="VBoxContainer"] 14 | layout_mode = 2 15 | text = "Content" 16 | 17 | [node name="TextEdit" type="TextEdit" parent="VBoxContainer"] 18 | layout_mode = 2 19 | size_flags_vertical = 3 20 | placeholder_text = "O Captain! My Captain! 21 | 22 | " 23 | wrap_mode = 1 24 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/end_node.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://b4p5xpw070bdj"] 2 | 3 | [ext_resource type="Theme" uid="uid://dialggjrx4vmt" path="res://addons/eazy_dialog/node_style.tres" id="1_lncs0"] 4 | 5 | [node name="END" type="GraphNode"] 6 | theme = ExtResource("1_lncs0") 7 | resizable = true 8 | title = "END" 9 | slot/0/left_enabled = true 10 | slot/0/left_type = 0 11 | slot/0/left_color = Color(0.556863, 0.937255, 0.592157, 1) 12 | slot/0/left_icon = null 13 | slot/0/right_enabled = false 14 | slot/0/right_type = 0 15 | slot/0/right_color = Color(1, 1, 1, 1) 16 | slot/0/right_icon = null 17 | slot/0/draw_stylebox = true 18 | 19 | [node name="Label" type="Label" parent="."] 20 | layout_mode = 2 21 | text = "END" 22 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/editor/dialog_edit.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://dgsi83vnjytcd"] 2 | 3 | [ext_resource type="Script" uid="uid://b5slpjeiuqkgl" path="res://addons/eazy_dialog/components/editor/dialog_edit.gd" id="1_qqjym"] 4 | 5 | [node name="DialogEdit" type="GraphEdit"] 6 | size_flags_horizontal = 3 7 | size_flags_vertical = 3 8 | size_flags_stretch_ratio = 5.0 9 | theme_override_colors/selection_stroke = Color(0.556863, 0.937255, 0.592157, 1) 10 | grid_pattern = 1 11 | right_disconnects = true 12 | show_zoom_label = true 13 | script = ExtResource("1_qqjym") 14 | 15 | [connection signal="connection_request" from="." to="." method="_on_connection_request"] 16 | [connection signal="delete_nodes_request" from="." to="." method="_on_delete_nodes_request"] 17 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/start_node.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://b8fu3clan4c14"] 2 | 3 | [ext_resource type="Theme" uid="uid://dialggjrx4vmt" path="res://addons/eazy_dialog/node_style.tres" id="1_phmxm"] 4 | 5 | [node name="START" type="GraphNode"] 6 | offset_right = 234.0 7 | offset_bottom = 86.0 8 | theme = ExtResource("1_phmxm") 9 | resizable = true 10 | title = "START" 11 | slot/0/left_enabled = false 12 | slot/0/left_type = 0 13 | slot/0/left_color = Color(1, 1, 1, 1) 14 | slot/0/left_icon = null 15 | slot/0/right_enabled = true 16 | slot/0/right_type = 0 17 | slot/0/right_color = Color(0.556863, 0.937255, 0.592157, 1) 18 | slot/0/right_icon = null 19 | slot/0/draw_stylebox = true 20 | 21 | [node name="HBoxContainer" type="HBoxContainer" parent="."] 22 | layout_mode = 2 23 | size_flags_vertical = 3 24 | 25 | [node name="Label" type="Label" parent="HBoxContainer"] 26 | layout_mode = 2 27 | size_flags_horizontal = 6 28 | text = "Dialog Name" 29 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/item_dialog.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=3 uid="uid://c6mgh5y4vkyp8"] 2 | 3 | [ext_resource type="Script" uid="uid://bj6jmv62yd5kf" path="res://addons/eazy_dialog/components/item.gd" id="1_co6sr"] 4 | [ext_resource type="Texture2D" uid="uid://oreb7ri1w86p" path="res://addons/eazy_dialog/icon/delete.svg" id="1_yrnnd"] 5 | 6 | [node name="ItemDialog" type="HBoxContainer"] 7 | custom_minimum_size = Vector2(100, 30) 8 | offset_right = 298.0 9 | offset_bottom = 41.0 10 | size_flags_horizontal = 3 11 | size_flags_vertical = 3 12 | script = ExtResource("1_co6sr") 13 | 14 | [node name="TextEdit" type="TextEdit" parent="."] 15 | layout_mode = 2 16 | size_flags_horizontal = 3 17 | wrap_mode = 1 18 | 19 | [node name="Button" type="Button" parent="."] 20 | layout_mode = 2 21 | size_flags_horizontal = 4 22 | size_flags_vertical = 4 23 | icon = ExtResource("1_yrnnd") 24 | flat = true 25 | 26 | [connection signal="pressed" from="Button" to="." method="_on_button_pressed"] 27 | -------------------------------------------------------------------------------- /addons/eazy_dialog/icon/add_character.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /addons/eazy_dialog/icon/add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /addons/eazy_dialog/icon/save.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /addons/eazy_dialog/plugin.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends EditorPlugin 3 | 4 | 5 | const MainPanel =preload("res://addons/eazy_dialog/main.tscn") 6 | var main_panel_instance 7 | var inspector_plugin 8 | 9 | 10 | 11 | 12 | func _enter_tree(): 13 | main_panel_instance = MainPanel.instantiate() 14 | # Add the main panel to the editor's main viewport. 15 | EditorInterface.get_editor_main_screen().add_child(main_panel_instance) 16 | # Hide the main panel. Very much required. 17 | _make_visible(false) 18 | var dir = DirAccess.open("res://") 19 | if not dir.dir_exists("res://eazy_dialog_data"): 20 | dir.make_dir("res://eazy_dialog_data") 21 | save_text_to_cfg() 22 | 23 | 24 | 25 | 26 | func _exit_tree(): 27 | if main_panel_instance: 28 | main_panel_instance.queue_free() 29 | 30 | 31 | 32 | 33 | func _has_main_screen(): 34 | return true 35 | 36 | 37 | func _make_visible(visible): 38 | if main_panel_instance: 39 | main_panel_instance.visible = visible 40 | 41 | 42 | func _get_plugin_name(): 43 | return "Eazy Dialog" 44 | 45 | 46 | func _get_plugin_icon(): 47 | # Must return some kind of Texture for the icon. 48 | return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons") 49 | 50 | 51 | # 保存文本到 .cfg 文件 52 | func save_text_to_cfg(): 53 | # 创建新的 ConfigFile 对象。 54 | var config = ConfigFile.new() 55 | if config.load("res://eazy_dialog_data/data.cfg") != OK: 56 | config.set_value("EazyDialog", "Character", "") 57 | config.save("res://eazy_dialog_data/data.cfg") 58 | _refresh_filesystem() 59 | 60 | func _refresh_filesystem(): 61 | var a = EditorInterface.get_resource_filesystem() 62 | a.scan() 63 | -------------------------------------------------------------------------------- /addons/eazy_dialog/eazy_dialog_runtime.gd: -------------------------------------------------------------------------------- 1 | class_name EazyDialogRuntime extends Node 2 | 3 | const runtime_cs = preload("res://addons/eazy_dialog/components/EazyDialogRuntime.cs") 4 | var runtime 5 | var _name:Label 6 | var _content:Label 7 | var _item_list: ItemList 8 | var _dialog_file:String 9 | 10 | signal dialog_start() 11 | signal dialog_play(character:String,content:String) 12 | signal dialog_selection_show(answers:Array) 13 | signal dialog_end() 14 | 15 | 16 | func _init(dialog_file:String,nameLabel:Label,contentLabel:Label,item_list: ItemList) -> void: 17 | _name = nameLabel 18 | _content = contentLabel 19 | _item_list = item_list 20 | _dialog_file = dialog_file 21 | 22 | runtime = runtime_cs.new() 23 | runtime.DialogueSignal.connect(_dialogue_signal) 24 | runtime.DialogueSelectionSignal.connect(_dialogue_selection_signal) 25 | runtime.DialogueEndSignal.connect(_dialogue_end_signal) 26 | if(!item_list.item_selected.has_connections()): 27 | item_list.item_selected.connect(_on_item_list_item_selected) 28 | runtime.PlayNext(_dialog_file,-1) 29 | call_deferred("emit_signal", "dialog_start") 30 | 31 | 32 | func play()->void: 33 | runtime.PlayNext(_dialog_file,-1) 34 | 35 | func _dialogue_signal(character:String,content:String)->void: 36 | _name.text = character 37 | _content.text = content 38 | dialog_play.emit(character,content) 39 | 40 | func _dialogue_selection_signal(answers:Array)->void: 41 | _item_list.clear() 42 | _item_list.visible = true 43 | for answer in answers: 44 | _item_list.add_item(answer) 45 | dialog_selection_show.emit(answers) 46 | 47 | 48 | func _dialogue_end_signal()->void: 49 | _item_list.clear() 50 | dialog_end.emit() 51 | self.queue_free() 52 | 53 | func _on_item_list_item_selected(index:int)->void: 54 | 55 | runtime.PlayNext(_dialog_file,index) 56 | 57 | _item_list.visible = false 58 | -------------------------------------------------------------------------------- /addons/eazy_dialog/icon/delete.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/dialog_node.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=3 uid="uid://rn53cgkwpy6"] 2 | 3 | [ext_resource type="PackedScene" uid="uid://dndw6nbqmg1ms" path="res://addons/eazy_dialog/components/dialog_context.tscn" id="2_7gcu4"] 4 | [ext_resource type="Texture2D" uid="uid://brfe7v7ea0h8k" path="res://addons/eazy_dialog/icon/add.svg" id="3_2e87v"] 5 | 6 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5qmam"] 7 | content_margin_left = 8.0 8 | bg_color = Color(0.0980392, 0.529412, 0.329412, 1) 9 | corner_radius_top_left = 8 10 | corner_radius_top_right = 8 11 | 12 | [node name="DialogNode" type="GraphNode"] 13 | offset_right = 294.0 14 | offset_bottom = 233.0 15 | size_flags_horizontal = 3 16 | size_flags_vertical = 3 17 | theme_override_styles/titlebar = SubResource("StyleBoxFlat_5qmam") 18 | resizable = true 19 | title = "Dialog" 20 | slot/0/left_enabled = true 21 | slot/0/left_type = 0 22 | slot/0/left_color = Color(0.556863, 0.937255, 0.592157, 1) 23 | slot/0/left_icon = null 24 | slot/0/right_enabled = true 25 | slot/0/right_type = 0 26 | slot/0/right_color = Color(0.556863, 0.937255, 0.592157, 1) 27 | slot/0/right_icon = null 28 | slot/0/draw_stylebox = true 29 | 30 | [node name="HFlowContainer" type="VBoxContainer" parent="."] 31 | layout_mode = 2 32 | size_flags_vertical = 3 33 | 34 | [node name="HBoxContainer" type="HBoxContainer" parent="HFlowContainer"] 35 | layout_mode = 2 36 | 37 | [node name="Label" type="Label" parent="HFlowContainer/HBoxContainer"] 38 | layout_mode = 2 39 | text = "Character" 40 | 41 | [node name="OptionButton" type="OptionButton" parent="HFlowContainer/HBoxContainer"] 42 | layout_mode = 2 43 | size_flags_horizontal = 3 44 | 45 | [node name="VBoxContainer" type="VBoxContainer" parent="HFlowContainer"] 46 | layout_mode = 2 47 | size_flags_vertical = 3 48 | 49 | [node name="DialogContext" parent="HFlowContainer/VBoxContainer" instance=ExtResource("2_7gcu4")] 50 | clip_contents = true 51 | layout_mode = 2 52 | 53 | [node name="Button" type="Button" parent="HFlowContainer/VBoxContainer"] 54 | visible = false 55 | layout_mode = 2 56 | size_flags_horizontal = 4 57 | icon = ExtResource("3_2e87v") 58 | flat = true 59 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/muti_node.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=3 uid="uid://be0tywtto5t4f"] 2 | 3 | [ext_resource type="Script" uid="uid://cs5vg5fxtrcjb" path="res://addons/eazy_dialog/components/muti_node.gd" id="1_1chja"] 4 | [ext_resource type="Texture2D" uid="uid://brfe7v7ea0h8k" path="res://addons/eazy_dialog/icon/add.svg" id="2_m56ld"] 5 | 6 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1chja"] 7 | content_margin_left = 8.0 8 | bg_color = Color(0.454902, 0.188235, 0.976471, 1) 9 | corner_radius_top_left = 8 10 | corner_radius_top_right = 8 11 | 12 | [node name="MutiNode" type="GraphNode"] 13 | offset_right = 228.0 14 | offset_bottom = 108.0 15 | size_flags_horizontal = 3 16 | size_flags_vertical = 3 17 | theme_override_styles/titlebar = SubResource("StyleBoxFlat_1chja") 18 | resizable = true 19 | title = "Selection" 20 | slot/0/left_enabled = true 21 | slot/0/left_type = 0 22 | slot/0/left_color = Color(1, 1, 1, 1) 23 | slot/0/left_icon = null 24 | slot/0/right_enabled = true 25 | slot/0/right_type = 0 26 | slot/0/right_color = Color(1, 1, 1, 1) 27 | slot/0/right_icon = null 28 | slot/0/draw_stylebox = true 29 | script = ExtResource("1_1chja") 30 | 31 | [node name="VBoxContainer" type="VBoxContainer" parent="."] 32 | layout_mode = 2 33 | size_flags_vertical = 3 34 | 35 | [node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] 36 | layout_mode = 2 37 | 38 | [node name="Label" type="Label" parent="VBoxContainer/HBoxContainer"] 39 | layout_mode = 2 40 | text = "Character" 41 | 42 | [node name="OptionButton" type="OptionButton" parent="VBoxContainer/HBoxContainer"] 43 | layout_mode = 2 44 | size_flags_horizontal = 3 45 | 46 | [node name="Label" type="Label" parent="VBoxContainer"] 47 | layout_mode = 2 48 | text = "Selection" 49 | 50 | [node name="ItemContainer" type="VBoxContainer" parent="VBoxContainer"] 51 | unique_name_in_owner = true 52 | layout_mode = 2 53 | size_flags_horizontal = 3 54 | size_flags_vertical = 3 55 | 56 | [node name="AddItemButton" type="Button" parent="VBoxContainer"] 57 | layout_mode = 2 58 | size_flags_horizontal = 4 59 | icon = ExtResource("2_m56ld") 60 | flat = true 61 | 62 | [connection signal="pressed" from="VBoxContainer/AddItemButton" to="." method="_on_add_item_button_pressed"] 63 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/EazyDialogRuntime.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | using System.IO; 4 | using System.Collections.Generic; 5 | using EazyDialog.Resolver; 6 | 7 | namespace EazyDialog{ 8 | 9 | public class Dialogue 10 | { 11 | public string Character { get; set; } 12 | public string Content { get; set; } 13 | public List Selections { get; set; } = new List(); 14 | public List Left { get; set; } = new List(); 15 | public List Right { get; set; } = new List(); 16 | } 17 | 18 | namespace Runtime{ 19 | 20 | 21 | public partial class EazyDialogRuntime : Node 22 | { 23 | 24 | [Signal] 25 | public delegate void DialogueSignalEventHandler(string character,string content); 26 | [Signal] 27 | public delegate void DialogueSelectionSignalEventHandler(Godot.Collections.Array answers); 28 | 29 | [Signal] 30 | public delegate void DialogueEndSignalEventHandler(); 31 | 32 | private static Random _random = new Random(); 33 | private string dialogName; 34 | private Dictionary dialogs = null; 35 | 36 | private EazyDialogResolver resolver = new EazyDialogResolver(); 37 | 38 | public void PlayNext(string dialogFile,int index ){ 39 | if(dialogs == null){ 40 | dialogs = resolver.ParseFile(dialogFile); 41 | var startRight = dialogs["START"].Right; 42 | dialogName = startRight[0]; 43 | } 44 | 45 | if(dialogName =="END"){ 46 | dialogs = null; 47 | dialogName = null; 48 | EmitSignal(SignalName.DialogueEndSignal); 49 | return; 50 | 51 | } 52 | 53 | if(index != -1){ 54 | GD.Print(index); 55 | dialogName = dialogs[dialogName].Right[index]; 56 | } 57 | 58 | if(dialogs[dialogName].Right.Count>0){ 59 | 60 | 61 | if(dialogs[dialogName].Right[0].StartsWith("Mutiple")){ 62 | 63 | Godot.Collections.Array mAnswers = new Godot.Collections.Array(); 64 | 65 | if(dialogs[dialogs[dialogName].Right[0]].Selections.Count >0){ 66 | foreach (string selection in dialogs[dialogs[dialogName].Right[0]].Selections){ 67 | mAnswers.Add(selection); 68 | } 69 | EmitSignal(SignalName.DialogueSelectionSignal, mAnswers);} 70 | 71 | }} 72 | 73 | 74 | if(dialogName.StartsWith("Dialog")){ 75 | string characterName = dialogs[dialogName].Character; 76 | string nextContent = dialogs[dialogName].Content; 77 | dialogName = dialogs[dialogName].Right[0]; 78 | EmitSignal(SignalName.DialogueSignal, characterName,nextContent); 79 | 80 | } 81 | 82 | 83 | 84 | 85 | 86 | } 87 | 88 | 89 | 90 | } 91 | 92 | 93 | } 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | } 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/Resolver.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | using EazyDialog; 4 | using System.IO; 5 | using System.Collections.Generic; 6 | 7 | namespace EazyDialog.Resolver{ 8 | public partial class EazyDialogResolver : Node 9 | { 10 | public Dictionary ParseFile(string dialogFile){ 11 | string mainCharacter = GetNthLastDirectory(dialogFile, 2); 12 | string secondaryCharacter = GetNthLastDirectory(dialogFile, 1); 13 | string context = LoadFile(dialogFile); 14 | var dialogues = new Dictionary(); 15 | var lines = context.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); 16 | 17 | Dialogue currentDialogue = null; 18 | string currentKey = null; 19 | string currentSection = null; 20 | foreach (var line in lines) 21 | { 22 | string trimmed = line.Trim(); 23 | 24 | if (trimmed.StartsWith("[") && trimmed.EndsWith("]")) 25 | { 26 | currentKey = trimmed.Trim('[', ']'); 27 | currentDialogue = new Dialogue { }; 28 | dialogues[currentKey] = currentDialogue; 29 | } 30 | else if (trimmed.Equals("Character")) 31 | { 32 | currentSection = "Character"; 33 | } 34 | else if (trimmed.Equals("Context")) 35 | { 36 | currentSection = "Context"; 37 | } 38 | else if (trimmed.Equals("LEFT")) 39 | { 40 | currentSection = "LEFT"; 41 | } 42 | else if (trimmed.Equals("RIGHT")) 43 | { 44 | currentSection = "RIGHT"; 45 | } 46 | else if (trimmed.Equals("Selections")) 47 | { 48 | currentSection = "Selections"; 49 | } 50 | else if (trimmed.StartsWith("- ")) 51 | { 52 | string content = trimmed.Substring(2).Trim(); 53 | if (currentDialogue != null && currentSection != null) 54 | { 55 | if(currentSection == "Character"){ 56 | currentDialogue.Character = content; 57 | 58 | } 59 | else if (currentSection == "Context") 60 | { 61 | currentDialogue.Content += (string.IsNullOrEmpty(currentDialogue.Content) ? "" : "\n") + content; 62 | } 63 | else if (currentSection == "LEFT") 64 | { 65 | currentDialogue.Left.Add(content); 66 | } 67 | else if (currentSection == "RIGHT") 68 | { 69 | currentDialogue.Right.Add(content); 70 | } 71 | else if (currentSection == "Selections") 72 | { 73 | currentDialogue.Selections.Add(content); 74 | } 75 | } 76 | } 77 | else{ 78 | if (currentSection == "Context") 79 | { 80 | currentDialogue.Content += (string.IsNullOrEmpty(currentDialogue.Content) ? "" : "\n") + trimmed; 81 | } 82 | } 83 | } 84 | 85 | return dialogues; 86 | 87 | } 88 | 89 | public List GetCharacters(string dialogFile){ 90 | List characters = new(); 91 | DirectoryInfo dirInfo = new DirectoryInfo(dialogFile); 92 | string primary = dirInfo.Parent?.Name ?? "无"; 93 | string secondary = dirInfo.Parent.Parent.Name; 94 | characters.Add(primary); 95 | characters.Add(secondary); 96 | 97 | return characters; 98 | } 99 | 100 | private string GetNthLastDirectory(string filePath, int n) 101 | { 102 | string directoryPath = Path.GetDirectoryName(filePath); // 获取文件所在的目录 103 | if (directoryPath == null) return "无效路径"; 104 | 105 | string[] folders = directoryPath.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); 106 | if (folders.Length < n) return "文件夹数量不足"; 107 | 108 | return folders[folders.Length - n]; // 取倒数第 n 个文件夹 109 | } 110 | 111 | 112 | private string LoadFile(string filePath) 113 | { 114 | using var file = Godot.FileAccess.Open(filePath, Godot.FileAccess.ModeFlags.Read); 115 | string content = file.GetAsText(); 116 | return content; 117 | } 118 | 119 | 120 | 121 | 122 | } 123 | } -------------------------------------------------------------------------------- /addons/eazy_dialog/icon/dialog_text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /addons/eazy_dialog/main.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends Node 3 | @onready var new_button: Button = %newButton 4 | @onready var text_edit: TextEdit = $NewCharacterDialog/TextEdit 5 | @onready var new_character_dialog: ConfirmationDialog = $NewCharacterDialog 6 | @onready var content: HSplitContainer = $MarginContainer/HSplitContainer/VBoxContainer/MarginContainer/Content 7 | @onready var main_character_button: OptionButton = $NewSessionDialog/VBoxContainer/HBoxContainer/MainCharacterButton 8 | @onready var secondary_character_button: OptionButton = $NewSessionDialog/VBoxContainer/HBoxContainer2/SecondaryCharacterButton 9 | @onready var new_session_dialog: ConfirmationDialog = $NewSessionDialog 10 | @onready var dialog_name_edit: LineEdit = $NewSessionDialog/VBoxContainer/HBoxContainer3/DialogNameEdit 11 | @onready var file_dialog: FileDialog = $FileDialog 12 | 13 | const DIALOG_EDIT = preload("res://addons/eazy_dialog/components/editor/dialog_edit.tscn") 14 | var start_node = preload("res://addons/eazy_dialog/components/start_node.tscn") 15 | var dialog_node = preload("res://addons/eazy_dialog/components/dialog_node.tscn") 16 | var muti_node = preload("res://addons/eazy_dialog/components/muti_node.tscn") 17 | var end_node = preload("res://addons/eazy_dialog/components/end_node.tscn") 18 | const MUTI_NODE = preload("res://addons/eazy_dialog/components/muti_node.tscn") 19 | var index_Dialog = 0 20 | var index_Mutiple = 0 21 | var csharp_compiler = preload("res://addons/eazy_dialog/components/Compiler.cs") 22 | var main_character = "" 23 | var secondary_character = "" 24 | var dialog_name = "" 25 | var dialog_edit: GraphEdit 26 | 27 | func _ready() -> void: 28 | dialog_edit = DIALOG_EDIT.instantiate() 29 | 30 | func _on_new_character_button_pressed() -> void: 31 | new_character_dialog.popup_centered() 32 | 33 | 34 | func _on_new_button_pressed() -> void: 35 | var content = "" 36 | var config = ConfigFile.new() 37 | if config.load("res://eazy_dialog_data/data.cfg") == OK: 38 | content = config.get_value("EazyDialog", "Character","") 39 | print("Character:"+content) 40 | var parts = content.split("|") 41 | main_character_button.clear() 42 | secondary_character_button.clear() 43 | 44 | for part in parts: 45 | main_character_button.add_item(part) 46 | secondary_character_button.add_item(part) 47 | new_session_dialog.popup_centered() 48 | 49 | 50 | 51 | func _on_add_start_node_pressed() -> void: 52 | var node = start_node.instantiate() 53 | node.position_offset = dialog_edit.get_global_mouse_position() 54 | dialog_edit.add_child(node) 55 | 56 | 57 | func _on_add_dialog_node_pressed() -> void: 58 | var node:GraphNode = dialog_node.instantiate() 59 | node.position_offset = dialog_edit.get_screen_position() 60 | node.name = "Dialog_"+str(index_Dialog) 61 | node.title = "Dialog_"+str(index_Dialog) 62 | var optionButton:OptionButton = node.get_node("HFlowContainer/HBoxContainer/OptionButton") 63 | print("测试"+main_character+secondary_character) 64 | optionButton.add_item(main_character) 65 | optionButton.add_item(secondary_character) 66 | dialog_edit.add_child(node) 67 | index_Dialog+=1 68 | 69 | func _on_add_muti_node_pressed() -> void: 70 | var node:GraphNode = muti_node.instantiate() 71 | node.position_offset = dialog_edit.get_screen_position() 72 | node.name = "Mutiple_"+str(index_Mutiple) 73 | node.title = "Mutiple_"+str(index_Mutiple) 74 | var optionButton:OptionButton = node.get_node("VBoxContainer/HBoxContainer/OptionButton") 75 | optionButton.add_item(main_character) 76 | optionButton.add_item(secondary_character) 77 | dialog_edit.add_child(node) 78 | index_Mutiple+=1 79 | 80 | 81 | func _on_add_end_node_pressed() -> void: 82 | var node:GraphNode = end_node.instantiate() 83 | node.position_offset = dialog_edit.get_screen_position() 84 | dialog_edit.add_child(node) 85 | 86 | 87 | func _on_save_button_pressed() -> void: 88 | var csharp_compiler_node = csharp_compiler.new() 89 | var dir = DirAccess.open("res://") 90 | _create_folder("res://eazy_dialog_data/"+main_character+"/"+secondary_character) 91 | csharp_compiler_node.ExportGraph(dialog_edit,"res://eazy_dialog_data/"+main_character+"/"+secondary_character+"/"+dialog_name+".txt") 92 | _refresh_filesystem() 93 | 94 | 95 | 96 | 97 | func _on_new_character_dialog_confirmed() -> void: 98 | if (text_edit.text!=null): 99 | save_text_to_cfg(text_edit.text) 100 | 101 | 102 | 103 | # 保存文本到 .cfg 文件 104 | func save_text_to_cfg(character_name): 105 | # 创建新的 ConfigFile 对象。 106 | var config = ConfigFile.new() 107 | 108 | var file_path = "res://eazy_dialog_data/data.cfg" 109 | var content = "" 110 | if config.load(file_path) == OK: 111 | content = config.get_value("EazyDialog", "Character","") 112 | if(content == ""): 113 | content += character_name 114 | else : 115 | content = content + "|"+character_name 116 | 117 | config.set_value("EazyDialog", "Character",content) 118 | #DirAccess.remove_absolute(file_path) 119 | config.save(file_path) 120 | _refresh_filesystem() 121 | 122 | 123 | func _create_folder(path: String) -> void: 124 | var dir := DirAccess.open("res://") 125 | var current_path := "res://" 126 | for folder in path.replace("res://", "").split("/"): 127 | current_path += folder + "/" 128 | if not dir.dir_exists(current_path): 129 | dir.make_dir(current_path) 130 | print("Created folder: " + current_path) 131 | 132 | func _refresh_filesystem(): 133 | var fs = EditorInterface.get_resource_filesystem() 134 | fs.scan_sources() 135 | 136 | 137 | func _on_main_character_button_item_selected(index: int) -> void: 138 | main_character = main_character_button.get_item_text(index) 139 | print(main_character) 140 | 141 | func _on_secondary_character_button_item_selected(index: int) -> void: 142 | secondary_character = secondary_character_button.get_item_text(index) 143 | print(secondary_character) 144 | 145 | 146 | func _on_new_session_dialog_confirmed() -> void: 147 | dialog_name = dialog_name_edit.text 148 | var node:GraphNode = start_node.instantiate() 149 | var label:Label = node.get_node("HBoxContainer/Label") 150 | if (content.has_node("DialogEdit")): 151 | content.remove_child(dialog_edit) 152 | content.add_child(dialog_edit) 153 | content.move_child(dialog_edit,0) 154 | 155 | node.position_offset = dialog_edit.get_screen_position() 156 | label.text = dialog_name 157 | dialog_edit.add_child(node) 158 | main_character = main_character_button.get_item_text(main_character_button.get_selected_id()) 159 | secondary_character = secondary_character_button.get_item_text(secondary_character_button.get_selected_id()) 160 | index_Dialog = 0 161 | index_Mutiple = 0 162 | if(!content.visible): 163 | content.visible = true 164 | 165 | 166 | func _on_open_button_pressed() -> void: 167 | file_dialog.popup_centered() 168 | 169 | 170 | func _on_file_dialog_confirmed() -> void: 171 | var csharp_compiler_node = csharp_compiler.new() 172 | #csharp_compiler_node.FileToGraph("res://eazy_dialog_data/Cat/Chicken/A.txt",dialog_edit) 173 | if (content.has_node("DialogEdit")): 174 | content.remove_child(dialog_edit) 175 | content.add_child(dialog_edit) 176 | content.move_child(dialog_edit,0) 177 | 178 | csharp_compiler_node.FileToGraph(file_dialog.current_path,dialog_edit) 179 | 180 | 181 | func _on_dialog_edit_delete_nodes_request(nodes: Array[StringName]) -> void: 182 | pass # Replace with function body. 183 | 184 | 185 | func _on_dialog_edit_disconnection_request(from_node: StringName, from_port: int, to_node: StringName, to_port: int) -> void: 186 | pass # Replace with function body. 187 | -------------------------------------------------------------------------------- /addons/eazy_dialog/main_view.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends Node 3 | @onready var new_button: Button = %newButton 4 | @onready var text_edit: TextEdit = $NewCharacterDialog/TextEdit 5 | @onready var new_character_dialog: ConfirmationDialog = $NewCharacterDialog 6 | @onready var content: HSplitContainer = $MarginContainer/HSplitContainer/VBoxContainer/MarginContainer/Content 7 | @onready var main_character_button: OptionButton = $NewSessionDialog/VBoxContainer/HBoxContainer/MainCharacterButton 8 | @onready var secondary_character_button: OptionButton = $NewSessionDialog/VBoxContainer/HBoxContainer2/SecondaryCharacterButton 9 | @onready var new_session_dialog: ConfirmationDialog = $NewSessionDialog 10 | @onready var dialog_name_edit: LineEdit = $NewSessionDialog/VBoxContainer/HBoxContainer3/DialogNameEdit 11 | @onready var file_dialog: FileDialog = $FileDialog 12 | 13 | const DIALOG_EDIT = preload("res://addons/eazy_dialog/components/editor/dialog_edit.tscn") 14 | var start_node = preload("res://addons/eazy_dialog/components/start_node.tscn") 15 | var dialog_node = preload("res://addons/eazy_dialog/components/dialog_node.tscn") 16 | var muti_node = preload("res://addons/eazy_dialog/components/muti_node.tscn") 17 | var end_node = preload("res://addons/eazy_dialog/components/end_node.tscn") 18 | const MUTI_NODE = preload("res://addons/eazy_dialog/components/muti_node.tscn") 19 | var index_Dialog = 0 20 | var index_Mutiple = 0 21 | var csharp_compiler = preload("res://addons/eazy_dialog/components/Compiler.cs") 22 | var main_character = "" 23 | var secondary_character = "" 24 | var dialog_name = "" 25 | var dialog_edit: GraphEdit 26 | 27 | func _ready() -> void: 28 | dialog_edit = DIALOG_EDIT.instantiate() 29 | 30 | func _on_new_character_button_pressed() -> void: 31 | new_character_dialog.popup_centered() 32 | 33 | 34 | func _on_new_button_pressed() -> void: 35 | var content = "" 36 | var config = ConfigFile.new() 37 | if config.load("res://eazy_dialog_data/data.cfg") == OK: 38 | content = config.get_value("EazyDialog", "Character","") 39 | print("Character:"+content) 40 | var parts = content.split("|") 41 | main_character_button.clear() 42 | secondary_character_button.clear() 43 | 44 | for part in parts: 45 | main_character_button.add_item(part) 46 | secondary_character_button.add_item(part) 47 | new_session_dialog.popup_centered() 48 | 49 | 50 | 51 | func _on_add_start_node_pressed() -> void: 52 | var node = start_node.instantiate() 53 | node.position_offset = dialog_edit.get_global_mouse_position() 54 | dialog_edit.add_child(node) 55 | 56 | 57 | func _on_add_dialog_node_pressed() -> void: 58 | var node:GraphNode = dialog_node.instantiate() 59 | node.position_offset = dialog_edit.get_screen_position() 60 | node.name = "Dialog_"+str(index_Dialog) 61 | node.title = "Dialog_"+str(index_Dialog) 62 | var optionButton:OptionButton = node.get_node("HFlowContainer/HBoxContainer/OptionButton") 63 | print("测试"+main_character+secondary_character) 64 | optionButton.add_item(main_character) 65 | optionButton.add_item(secondary_character) 66 | dialog_edit.add_child(node) 67 | index_Dialog+=1 68 | 69 | func _on_add_muti_node_pressed() -> void: 70 | var node:GraphNode = muti_node.instantiate() 71 | node.position_offset = dialog_edit.get_screen_position() 72 | node.name = "Mutiple_"+str(index_Mutiple) 73 | node.title = "Mutiple_"+str(index_Mutiple) 74 | var optionButton:OptionButton = node.get_node("VBoxContainer/HBoxContainer/OptionButton") 75 | optionButton.add_item(main_character) 76 | optionButton.add_item(secondary_character) 77 | dialog_edit.add_child(node) 78 | index_Mutiple+=1 79 | 80 | 81 | func _on_add_end_node_pressed() -> void: 82 | var node:GraphNode = end_node.instantiate() 83 | node.position_offset = dialog_edit.get_screen_position() 84 | dialog_edit.add_child(node) 85 | 86 | 87 | func _on_save_button_pressed() -> void: 88 | var csharp_compiler_node = csharp_compiler.new() 89 | var dir = DirAccess.open("res://") 90 | _create_folder("res://eazy_dialog_data/"+main_character+"/"+secondary_character) 91 | csharp_compiler_node.ExportGraph(dialog_edit,"res://eazy_dialog_data/"+main_character+"/"+secondary_character+"/"+dialog_name+".txt") 92 | _refresh_filesystem() 93 | 94 | 95 | 96 | 97 | func _on_new_character_dialog_confirmed() -> void: 98 | if (text_edit.text!=null): 99 | save_text_to_cfg(text_edit.text) 100 | 101 | 102 | 103 | # 保存文本到 .cfg 文件 104 | func save_text_to_cfg(character_name): 105 | # 创建新的 ConfigFile 对象。 106 | var config = ConfigFile.new() 107 | 108 | var file_path = "res://eazy_dialog_data/data.cfg" 109 | var content = "" 110 | if config.load(file_path) == OK: 111 | content = config.get_value("EazyDialog", "Character","") 112 | if(content == ""): 113 | content += character_name 114 | else : 115 | content = content + "|"+character_name 116 | 117 | config.set_value("EazyDialog", "Character",content) 118 | #DirAccess.remove_absolute(file_path) 119 | config.save(file_path) 120 | _refresh_filesystem() 121 | 122 | 123 | func _create_folder(path: String) -> void: 124 | var dir := DirAccess.open("res://") 125 | var current_path := "res://" 126 | for folder in path.replace("res://", "").split("/"): 127 | current_path += folder + "/" 128 | if not dir.dir_exists(current_path): 129 | dir.make_dir(current_path) 130 | print("Created folder: " + current_path) 131 | 132 | func _refresh_filesystem(): 133 | var fs = EditorInterface.get_resource_filesystem() 134 | fs.scan_sources() 135 | 136 | 137 | func _on_main_character_button_item_selected(index: int) -> void: 138 | main_character = main_character_button.get_item_text(index) 139 | print(main_character) 140 | 141 | func _on_secondary_character_button_item_selected(index: int) -> void: 142 | secondary_character = secondary_character_button.get_item_text(index) 143 | print(secondary_character) 144 | 145 | 146 | func _on_new_session_dialog_confirmed() -> void: 147 | dialog_name = dialog_name_edit.text 148 | var node:GraphNode = start_node.instantiate() 149 | var label:Label = node.get_node("HBoxContainer/Label") 150 | if (content.has_node("DialogEdit")): 151 | content.remove_child(dialog_edit) 152 | content.add_child(dialog_edit) 153 | content.move_child(dialog_edit,0) 154 | 155 | node.position_offset = dialog_edit.get_screen_position() 156 | label.text = dialog_name 157 | dialog_edit.add_child(node) 158 | main_character = main_character_button.get_item_text(main_character_button.get_selected_id()) 159 | secondary_character = secondary_character_button.get_item_text(secondary_character_button.get_selected_id()) 160 | index_Dialog = 0 161 | index_Mutiple = 0 162 | main_character = "" 163 | secondary_character = "" 164 | dialog_name = "" 165 | if(!content.visible): 166 | content.visible = true 167 | 168 | 169 | func _on_open_button_pressed() -> void: 170 | file_dialog.popup_centered() 171 | 172 | 173 | func _on_file_dialog_confirmed() -> void: 174 | var csharp_compiler_node = csharp_compiler.new() 175 | #csharp_compiler_node.FileToGraph("res://eazy_dialog_data/Cat/Chicken/A.txt",dialog_edit) 176 | if (content.has_node("DialogEdit")): 177 | content.remove_child(dialog_edit) 178 | content.add_child(dialog_edit) 179 | content.move_child(dialog_edit,0) 180 | 181 | csharp_compiler_node.FileToGraph(file_dialog.current_path,dialog_edit) 182 | 183 | 184 | func _on_dialog_edit_delete_nodes_request(nodes: Array[StringName]) -> void: 185 | pass # Replace with function body. 186 | 187 | 188 | func _on_dialog_edit_disconnection_request(from_node: StringName, from_port: int, to_node: StringName, to_port: int) -> void: 189 | pass # Replace with function body. 190 | -------------------------------------------------------------------------------- /addons/eazy_dialog/eazy_dialog.tscn16798228990.tmp: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=6 format=3 uid="uid://dqcvihf76dpx1"] 2 | 3 | [ext_resource type="Script" uid="uid://bgaq00g2th64d" path="res://addons/eazy_dialog/main.gd" id="1_8mdd1"] 4 | [ext_resource type="Texture2D" uid="uid://brfe7v7ea0h8k" path="res://addons/eazy_dialog/icon/add.svg" id="1_ls5wj"] 5 | [ext_resource type="Texture2D" uid="uid://bpl30vnsef15x" path="res://addons/eazy_dialog/icon/add_character.svg" id="3_cub2t"] 6 | [ext_resource type="Script" uid="uid://b0xyf2wj8bo7j" path="res://addons/eazy_dialog/dialog_edit.gd" id="4_gv8kj"] 7 | [ext_resource type="Texture2D" uid="uid://dgrroyjmi6eeo" path="res://addons/eazy_dialog/icon/save.svg" id="4_kgaqg"] 8 | 9 | [node name="Eazy Dialog" type="Control"] 10 | layout_mode = 3 11 | anchors_preset = 15 12 | anchor_right = 1.0 13 | anchor_bottom = 1.0 14 | grow_horizontal = 2 15 | grow_vertical = 2 16 | size_flags_horizontal = 3 17 | size_flags_vertical = 3 18 | script = ExtResource("1_8mdd1") 19 | 20 | [node name="NewCharacterDialog" type="ConfirmationDialog" parent="."] 21 | title = "添加角色" 22 | position = Vector2i(476, 274) 23 | 24 | [node name="TextEdit" type="TextEdit" parent="NewCharacterDialog"] 25 | offset_left = 8.0 26 | offset_top = 8.0 27 | offset_right = 192.0 28 | offset_bottom = 51.0 29 | 30 | [node name="MarginContainer" type="MarginContainer" parent="."] 31 | layout_mode = 1 32 | anchors_preset = 15 33 | anchor_right = 1.0 34 | anchor_bottom = 1.0 35 | offset_right = 0.0300293 36 | grow_horizontal = 2 37 | grow_vertical = 2 38 | 39 | [node name="Panel" type="Panel" parent="MarginContainer"] 40 | layout_mode = 2 41 | size_flags_horizontal = 3 42 | 43 | [node name="HSplitContainer" type="HSplitContainer" parent="MarginContainer"] 44 | layout_mode = 2 45 | dragger_visibility = 1 46 | 47 | [node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/HSplitContainer"] 48 | custom_minimum_size = Vector2(150, 0) 49 | layout_mode = 2 50 | size_flags_horizontal = 3 51 | 52 | [node name="ToolBar" type="HBoxContainer" parent="MarginContainer/HSplitContainer/VBoxContainer"] 53 | layout_mode = 2 54 | 55 | [node name="newButton" type="Button" parent="MarginContainer/HSplitContainer/VBoxContainer/ToolBar"] 56 | unique_name_in_owner = true 57 | layout_mode = 2 58 | tooltip_text = "添加对话 59 | " 60 | text = "创建对话" 61 | icon = ExtResource("1_ls5wj") 62 | flat = true 63 | 64 | [node name="newCharacterButton" type="Button" parent="MarginContainer/HSplitContainer/VBoxContainer/ToolBar"] 65 | unique_name_in_owner = true 66 | layout_mode = 2 67 | tooltip_text = "添加角色 68 | " 69 | text = "创建角色 70 | " 71 | icon = ExtResource("3_cub2t") 72 | flat = true 73 | 74 | [node name="SaveButton" type="Button" parent="MarginContainer/HSplitContainer/VBoxContainer/ToolBar"] 75 | layout_mode = 2 76 | text = "保存" 77 | icon = ExtResource("4_kgaqg") 78 | flat = true 79 | 80 | [node name="HSeparator" type="HSeparator" parent="MarginContainer/HSplitContainer/VBoxContainer"] 81 | layout_mode = 2 82 | 83 | [node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/HSplitContainer/VBoxContainer"] 84 | visible = false 85 | layout_mode = 2 86 | size_flags_vertical = 3 87 | 88 | [node name="DialogEdit" type="GraphEdit" parent="MarginContainer/HSplitContainer/VBoxContainer/HBoxContainer"] 89 | unique_name_in_owner = true 90 | clip_contents = false 91 | layout_mode = 2 92 | size_flags_horizontal = 3 93 | size_flags_vertical = 3 94 | size_flags_stretch_ratio = 5.0 95 | theme_override_colors/selection_stroke = Color(0.556863, 0.937255, 0.592157, 1) 96 | show_zoom_label = true 97 | script = ExtResource("4_gv8kj") 98 | 99 | [node name="VSeparator" type="VSeparator" parent="MarginContainer/HSplitContainer/VBoxContainer/HBoxContainer"] 100 | layout_mode = 2 101 | 102 | [node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/HSplitContainer/VBoxContainer/HBoxContainer"] 103 | layout_mode = 2 104 | size_flags_horizontal = 3 105 | 106 | [node name="Label" type="Label" parent="MarginContainer/HSplitContainer/VBoxContainer/HBoxContainer/VBoxContainer"] 107 | layout_mode = 2 108 | text = "添加结点" 109 | 110 | [node name="AddStartNode" type="Button" parent="MarginContainer/HSplitContainer/VBoxContainer/HBoxContainer/VBoxContainer"] 111 | layout_mode = 2 112 | text = "开始结点" 113 | 114 | [node name="AddDialogNode" type="Button" parent="MarginContainer/HSplitContainer/VBoxContainer/HBoxContainer/VBoxContainer"] 115 | layout_mode = 2 116 | text = "对话结点" 117 | 118 | [node name="AddEndNode" type="Button" parent="MarginContainer/HSplitContainer/VBoxContainer/HBoxContainer/VBoxContainer"] 119 | layout_mode = 2 120 | text = "结束结点" 121 | 122 | [node name="NewSessionDialog" type="ConfirmationDialog" parent="."] 123 | title = "创建对话" 124 | initial_position = 1 125 | size = Vector2i(200, 139) 126 | 127 | [node name="VBoxContainer" type="VBoxContainer" parent="NewSessionDialog"] 128 | offset_left = 8.0 129 | offset_top = 8.0 130 | offset_right = 192.0 131 | offset_bottom = 90.0 132 | 133 | [node name="HBoxContainer" type="HBoxContainer" parent="NewSessionDialog/VBoxContainer"] 134 | layout_mode = 2 135 | 136 | [node name="Label" type="Label" parent="NewSessionDialog/VBoxContainer/HBoxContainer"] 137 | layout_mode = 2 138 | text = "角色1" 139 | 140 | [node name="MainCharacterButton" type="OptionButton" parent="NewSessionDialog/VBoxContainer/HBoxContainer"] 141 | layout_mode = 2 142 | size_flags_horizontal = 3 143 | 144 | [node name="HBoxContainer2" type="HBoxContainer" parent="NewSessionDialog/VBoxContainer"] 145 | layout_mode = 2 146 | 147 | [node name="Label" type="Label" parent="NewSessionDialog/VBoxContainer/HBoxContainer2"] 148 | layout_mode = 2 149 | text = "角色2" 150 | 151 | [node name="SecondaryCharacterButton" type="OptionButton" parent="NewSessionDialog/VBoxContainer/HBoxContainer2"] 152 | layout_mode = 2 153 | size_flags_horizontal = 3 154 | 155 | [node name="HBoxContainer3" type="HBoxContainer" parent="NewSessionDialog/VBoxContainer"] 156 | layout_mode = 2 157 | 158 | [node name="Label" type="Label" parent="NewSessionDialog/VBoxContainer/HBoxContainer3"] 159 | layout_mode = 2 160 | text = "对话名称" 161 | 162 | [node name="DialogNameEdit" type="LineEdit" parent="NewSessionDialog/VBoxContainer/HBoxContainer3"] 163 | layout_mode = 2 164 | size_flags_horizontal = 3 165 | 166 | [connection signal="confirmed" from="NewCharacterDialog" to="." method="_on_new_character_dialog_confirmed"] 167 | [connection signal="pressed" from="MarginContainer/HSplitContainer/VBoxContainer/ToolBar/newButton" to="." method="_on_new_button_pressed"] 168 | [connection signal="pressed" from="MarginContainer/HSplitContainer/VBoxContainer/ToolBar/newCharacterButton" to="." method="_on_new_character_button_pressed"] 169 | [connection signal="pressed" from="MarginContainer/HSplitContainer/VBoxContainer/ToolBar/SaveButton" to="." method="_on_save_button_pressed"] 170 | [connection signal="pressed" from="MarginContainer/HSplitContainer/VBoxContainer/HBoxContainer/VBoxContainer/AddStartNode" to="." method="_on_add_start_node_pressed"] 171 | [connection signal="pressed" from="MarginContainer/HSplitContainer/VBoxContainer/HBoxContainer/VBoxContainer/AddDialogNode" to="." method="_on_add_dialog_node_pressed"] 172 | [connection signal="pressed" from="MarginContainer/HSplitContainer/VBoxContainer/HBoxContainer/VBoxContainer/AddEndNode" to="." method="_on_add_end_node_pressed"] 173 | [connection signal="confirmed" from="NewSessionDialog" to="." method="_on_new_session_dialog_confirmed"] 174 | [connection signal="item_selected" from="NewSessionDialog/VBoxContainer/HBoxContainer/MainCharacterButton" to="." method="_on_main_character_button_item_selected"] 175 | [connection signal="item_selected" from="NewSessionDialog/VBoxContainer/HBoxContainer2/SecondaryCharacterButton" to="." method="_on_secondary_character_button_item_selected"] 176 | -------------------------------------------------------------------------------- /addons/eazy_dialog/icon/dialog.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /addons/eazy_dialog/main.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=11 format=3 uid="uid://dqcvihf76dpx1"] 2 | 3 | [ext_resource type="Script" uid="uid://bgaq00g2th64d" path="res://addons/eazy_dialog/main_view.gd" id="1_4wxcw"] 4 | [ext_resource type="Texture2D" uid="uid://brfe7v7ea0h8k" path="res://addons/eazy_dialog/icon/add.svg" id="2_bkuf4"] 5 | [ext_resource type="Texture2D" uid="uid://bpl30vnsef15x" path="res://addons/eazy_dialog/icon/add_character.svg" id="3_652i0"] 6 | [ext_resource type="Texture2D" uid="uid://dgrroyjmi6eeo" path="res://addons/eazy_dialog/icon/save.svg" id="4_mm8bl"] 7 | [ext_resource type="Texture2D" uid="uid://bma1mbgscsf2d" path="res://addons/eazy_dialog/icon/file.svg" id="5_bg2r5"] 8 | 9 | [sub_resource type="CompressedTexture2D" id="CompressedTexture2D_fd25j"] 10 | 11 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fd25j"] 12 | bg_color = Color(0.0509804, 0.431373, 0.992157, 1) 13 | 14 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_twdvk"] 15 | bg_color = Color(0.0980392, 0.529412, 0.329412, 1) 16 | 17 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ad5ia"] 18 | bg_color = Color(0.454902, 0.188235, 0.976471, 1) 19 | 20 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_lyc3t"] 21 | bg_color = Color(0.0509804, 0.431373, 0.992157, 1) 22 | 23 | [node name="Eazy Dialog" type="Control"] 24 | layout_mode = 3 25 | anchors_preset = 15 26 | anchor_right = 1.0 27 | anchor_bottom = 1.0 28 | grow_horizontal = 2 29 | grow_vertical = 2 30 | size_flags_horizontal = 3 31 | size_flags_vertical = 3 32 | script = ExtResource("1_4wxcw") 33 | 34 | [node name="NewCharacterDialog" type="ConfirmationDialog" parent="."] 35 | title = "添加角色" 36 | position = Vector2i(476, 274) 37 | 38 | [node name="TextEdit" type="TextEdit" parent="NewCharacterDialog"] 39 | offset_left = 8.0 40 | offset_top = 8.0 41 | offset_right = 192.0 42 | offset_bottom = 51.0 43 | 44 | [node name="MarginContainer" type="MarginContainer" parent="."] 45 | layout_mode = 1 46 | anchors_preset = 15 47 | anchor_right = 1.0 48 | anchor_bottom = 1.0 49 | offset_right = 0.0300293 50 | grow_horizontal = 2 51 | grow_vertical = 2 52 | 53 | [node name="Panel" type="Panel" parent="MarginContainer"] 54 | layout_mode = 2 55 | size_flags_horizontal = 3 56 | 57 | [node name="HSplitContainer" type="HSplitContainer" parent="MarginContainer"] 58 | layout_mode = 2 59 | dragger_visibility = 1 60 | 61 | [node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/HSplitContainer"] 62 | custom_minimum_size = Vector2(150, 0) 63 | layout_mode = 2 64 | size_flags_horizontal = 3 65 | 66 | [node name="ToolBar" type="HBoxContainer" parent="MarginContainer/HSplitContainer/VBoxContainer"] 67 | layout_mode = 2 68 | 69 | [node name="newButton" type="Button" parent="MarginContainer/HSplitContainer/VBoxContainer/ToolBar"] 70 | unique_name_in_owner = true 71 | layout_mode = 2 72 | tooltip_text = "添加对话 73 | " 74 | text = "创建对话" 75 | icon = ExtResource("2_bkuf4") 76 | flat = true 77 | 78 | [node name="newCharacterButton" type="Button" parent="MarginContainer/HSplitContainer/VBoxContainer/ToolBar"] 79 | unique_name_in_owner = true 80 | layout_mode = 2 81 | tooltip_text = "添加角色 82 | " 83 | text = "创建角色 84 | " 85 | icon = ExtResource("3_652i0") 86 | flat = true 87 | 88 | [node name="VSeparator" type="VSeparator" parent="MarginContainer/HSplitContainer/VBoxContainer/ToolBar"] 89 | layout_mode = 2 90 | 91 | [node name="SaveButton" type="Button" parent="MarginContainer/HSplitContainer/VBoxContainer/ToolBar"] 92 | layout_mode = 2 93 | text = "保存" 94 | icon = ExtResource("4_mm8bl") 95 | flat = true 96 | 97 | [node name="OpenButton" type="Button" parent="MarginContainer/HSplitContainer/VBoxContainer/ToolBar"] 98 | layout_mode = 2 99 | text = "打开" 100 | icon = ExtResource("5_bg2r5") 101 | flat = true 102 | 103 | [node name="HSeparator" type="HSeparator" parent="MarginContainer/HSplitContainer/VBoxContainer"] 104 | layout_mode = 2 105 | 106 | [node name="MarginContainer" type="MarginContainer" parent="MarginContainer/HSplitContainer/VBoxContainer"] 107 | layout_mode = 2 108 | size_flags_vertical = 3 109 | 110 | [node name="TextureRect" type="TextureRect" parent="MarginContainer/HSplitContainer/VBoxContainer/MarginContainer"] 111 | visible = false 112 | layout_mode = 2 113 | texture = SubResource("CompressedTexture2D_fd25j") 114 | 115 | [node name="Content" type="HSplitContainer" parent="MarginContainer/HSplitContainer/VBoxContainer/MarginContainer"] 116 | visible = false 117 | layout_mode = 2 118 | size_flags_vertical = 3 119 | 120 | [node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/HSplitContainer/VBoxContainer/MarginContainer/Content"] 121 | layout_mode = 2 122 | size_flags_horizontal = 3 123 | 124 | [node name="Label" type="Label" parent="MarginContainer/HSplitContainer/VBoxContainer/MarginContainer/Content/VBoxContainer"] 125 | layout_mode = 2 126 | text = "添加结点" 127 | 128 | [node name="AddStartNode" type="Button" parent="MarginContainer/HSplitContainer/VBoxContainer/MarginContainer/Content/VBoxContainer"] 129 | layout_mode = 2 130 | theme_override_styles/normal = SubResource("StyleBoxFlat_fd25j") 131 | text = "开始结点" 132 | 133 | [node name="AddDialogNode" type="Button" parent="MarginContainer/HSplitContainer/VBoxContainer/MarginContainer/Content/VBoxContainer"] 134 | layout_mode = 2 135 | theme_override_styles/normal = SubResource("StyleBoxFlat_twdvk") 136 | text = "对话结点" 137 | 138 | [node name="AddMutiNode" type="Button" parent="MarginContainer/HSplitContainer/VBoxContainer/MarginContainer/Content/VBoxContainer"] 139 | layout_mode = 2 140 | theme_override_styles/normal = SubResource("StyleBoxFlat_ad5ia") 141 | text = "选项节点" 142 | 143 | [node name="AddEndNode" type="Button" parent="MarginContainer/HSplitContainer/VBoxContainer/MarginContainer/Content/VBoxContainer"] 144 | layout_mode = 2 145 | theme_override_styles/normal = SubResource("StyleBoxFlat_lyc3t") 146 | text = "结束结点" 147 | 148 | [node name="NewSessionDialog" type="ConfirmationDialog" parent="."] 149 | title = "创建对话" 150 | initial_position = 1 151 | size = Vector2i(200, 139) 152 | 153 | [node name="VBoxContainer" type="VBoxContainer" parent="NewSessionDialog"] 154 | offset_left = 8.0 155 | offset_top = 8.0 156 | offset_right = 192.0 157 | offset_bottom = 90.0 158 | 159 | [node name="HBoxContainer" type="HBoxContainer" parent="NewSessionDialog/VBoxContainer"] 160 | layout_mode = 2 161 | 162 | [node name="Label" type="Label" parent="NewSessionDialog/VBoxContainer/HBoxContainer"] 163 | layout_mode = 2 164 | text = "角色1" 165 | 166 | [node name="MainCharacterButton" type="OptionButton" parent="NewSessionDialog/VBoxContainer/HBoxContainer"] 167 | layout_mode = 2 168 | size_flags_horizontal = 3 169 | 170 | [node name="HBoxContainer2" type="HBoxContainer" parent="NewSessionDialog/VBoxContainer"] 171 | layout_mode = 2 172 | 173 | [node name="Label" type="Label" parent="NewSessionDialog/VBoxContainer/HBoxContainer2"] 174 | layout_mode = 2 175 | text = "角色2" 176 | 177 | [node name="SecondaryCharacterButton" type="OptionButton" parent="NewSessionDialog/VBoxContainer/HBoxContainer2"] 178 | layout_mode = 2 179 | size_flags_horizontal = 3 180 | 181 | [node name="HBoxContainer3" type="HBoxContainer" parent="NewSessionDialog/VBoxContainer"] 182 | layout_mode = 2 183 | 184 | [node name="Label" type="Label" parent="NewSessionDialog/VBoxContainer/HBoxContainer3"] 185 | layout_mode = 2 186 | text = "对话名称" 187 | 188 | [node name="DialogNameEdit" type="LineEdit" parent="NewSessionDialog/VBoxContainer/HBoxContainer3"] 189 | layout_mode = 2 190 | size_flags_horizontal = 3 191 | 192 | [node name="FileDialog" type="FileDialog" parent="."] 193 | title = "Open a File" 194 | initial_position = 1 195 | ok_button_text = "Open" 196 | file_mode = 0 197 | filters = PackedStringArray("*.txt") 198 | 199 | [connection signal="confirmed" from="NewCharacterDialog" to="." method="_on_new_character_dialog_confirmed"] 200 | [connection signal="pressed" from="MarginContainer/HSplitContainer/VBoxContainer/ToolBar/newButton" to="." method="_on_new_button_pressed"] 201 | [connection signal="pressed" from="MarginContainer/HSplitContainer/VBoxContainer/ToolBar/newCharacterButton" to="." method="_on_new_character_button_pressed"] 202 | [connection signal="pressed" from="MarginContainer/HSplitContainer/VBoxContainer/ToolBar/SaveButton" to="." method="_on_save_button_pressed"] 203 | [connection signal="pressed" from="MarginContainer/HSplitContainer/VBoxContainer/ToolBar/OpenButton" to="." method="_on_open_button_pressed"] 204 | [connection signal="pressed" from="MarginContainer/HSplitContainer/VBoxContainer/MarginContainer/Content/VBoxContainer/AddStartNode" to="." method="_on_add_start_node_pressed"] 205 | [connection signal="pressed" from="MarginContainer/HSplitContainer/VBoxContainer/MarginContainer/Content/VBoxContainer/AddDialogNode" to="." method="_on_add_dialog_node_pressed"] 206 | [connection signal="pressed" from="MarginContainer/HSplitContainer/VBoxContainer/MarginContainer/Content/VBoxContainer/AddMutiNode" to="." method="_on_add_muti_node_pressed"] 207 | [connection signal="pressed" from="MarginContainer/HSplitContainer/VBoxContainer/MarginContainer/Content/VBoxContainer/AddEndNode" to="." method="_on_add_end_node_pressed"] 208 | [connection signal="confirmed" from="NewSessionDialog" to="." method="_on_new_session_dialog_confirmed"] 209 | [connection signal="item_selected" from="NewSessionDialog/VBoxContainer/HBoxContainer/MainCharacterButton" to="." method="_on_main_character_button_item_selected"] 210 | [connection signal="item_selected" from="NewSessionDialog/VBoxContainer/HBoxContainer2/SecondaryCharacterButton" to="." method="_on_secondary_character_button_item_selected"] 211 | [connection signal="confirmed" from="FileDialog" to="." method="_on_file_dialog_confirmed"] 212 | -------------------------------------------------------------------------------- /addons/eazy_dialog/components/Compiler.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | using System.IO; 4 | using System.Collections.Generic; 5 | using EazyDialog.Resolver; 6 | using EazyDialog; 7 | using System.Linq; 8 | [Tool] 9 | public partial class Compiler : EditorPlugin 10 | { 11 | string nodeName = "START"; 12 | Vector2 position = new Vector2(0,0); 13 | Dictionary visited = new(); 14 | EazyDialogResolver resolver = new EazyDialogResolver(); 15 | Dictionary dialogs; 16 | List characterNames; 17 | PackedScene startNode = GD.Load("res://addons/eazy_dialog/components/start_node.tscn"); 18 | PackedScene endNode = GD.Load("res://addons/eazy_dialog/components/end_node.tscn"); 19 | PackedScene dialogNode = GD.Load("res://addons/eazy_dialog/components/dialog_node.tscn"); 20 | PackedScene mutipleNode = GD.Load("res://addons/eazy_dialog/components/muti_node.tscn"); 21 | 22 | PackedScene itemNode = GD.Load("res://addons/eazy_dialog/components/item_dialog.tscn"); 23 | 24 | public void ExportGraph(GraphEdit graphEdit,string savePath) 25 | { 26 | 27 | 28 | if (graphEdit == null) 29 | { 30 | GD.PrintErr("GraphEdit 未找到!"); 31 | return; 32 | } 33 | 34 | Dictionary> leftConnections = new(); 35 | Dictionary> rightConnections = new(); 36 | Dictionary> selections = new(); 37 | 38 | Dictionary context = new(); 39 | Dictionary character = new(); 40 | 41 | List dialogs = new(); 42 | 43 | 44 | // 获取所有 GraphNode 并分类 45 | foreach (var child in graphEdit.GetChildren()) 46 | { 47 | if (child is GraphNode graphNode) 48 | { 49 | string nodeTitle = graphNode.Title; 50 | dialogs.Add(nodeTitle); 51 | leftConnections[nodeTitle] = new List(); 52 | rightConnections[nodeTitle] = new List(); 53 | selections[nodeTitle] = new List(); 54 | context[nodeTitle] = ""; 55 | if (nodeTitle.Contains("Dialog")) 56 | { 57 | string dialogContent = child.GetNode("HFlowContainer/VBoxContainer/DialogContext/VBoxContainer/TextEdit").Text; 58 | string characterName = child.GetNode("HFlowContainer/HBoxContainer/OptionButton").Text; 59 | context[nodeTitle]=dialogContent; 60 | character[nodeTitle] = characterName; 61 | 62 | } 63 | else if(nodeTitle.Contains("Mutiple")){ 64 | VBoxContainer itemContainer = child.GetNode("VBoxContainer/ItemContainer"); 65 | string characterName = child.GetNode("VBoxContainer/HBoxContainer/OptionButton").Text; 66 | for(int i=0;i("TextEdit").Text); 68 | } 69 | character[nodeTitle] = characterName; 70 | } 71 | else{ 72 | context[nodeTitle] = "..."; 73 | character[nodeTitle] = "..."; 74 | 75 | } 76 | } 77 | } 78 | 79 | // 获取连接信息 80 | foreach (var connection in graphEdit.GetConnectionList()) 81 | { 82 | string fromNode = connection["from_node"].AsString(); 83 | string toNode = connection["to_node"].AsString(); 84 | int fromPort = connection["from_port"].AsInt32(); 85 | rightConnections[fromNode].Add(toNode); 86 | leftConnections[toNode].Add(fromNode); 87 | 88 | } 89 | 90 | 91 | string content = ""; 92 | 93 | foreach (var dialog in dialogs) 94 | { 95 | content += $"[{dialog}]\n"; 96 | content += $" Character\n"; 97 | content += $" - {character[dialog]}\n"; 98 | content += $" Context\n"; 99 | content += $" - {context[dialog]}\n"; 100 | 101 | if(selections[dialog].Count>0){ 102 | content += $" Selections\n"; 103 | foreach (var selection in selections[dialog]) 104 | { 105 | content += $" - {selection}\n"; 106 | } 107 | } 108 | 109 | // LEFT 110 | if (leftConnections[dialog].Count > 0) 111 | { 112 | content += $" LEFT\n"; 113 | foreach (var left in leftConnections[dialog]) 114 | { 115 | content += $" - {left}\n"; 116 | } 117 | } 118 | 119 | // RIGHT 120 | if (rightConnections[dialog].Count > 0) 121 | { 122 | content += $" RIGHT\n"; 123 | foreach (var right in rightConnections[dialog]) 124 | { 125 | content += $" - {right}\n"; 126 | } 127 | } 128 | content += "\n"; 129 | } 130 | WriteFile(savePath,content); 131 | 132 | 133 | 134 | GD.Print("Graph 数据已成功导出:\n ", content); 135 | } 136 | 137 | 138 | private void WriteFile(String path,string content) 139 | { 140 | 141 | using var file = Godot.FileAccess.Open(path, Godot.FileAccess.ModeFlags.Write); 142 | file.StoreString(content); 143 | } 144 | 145 | public void ConnectNode(GraphEdit graphEdit){ 146 | 147 | foreach(var _node in dialogs[nodeName].Right){ 148 | graphEdit.ConnectNode(nodeName,0,_node,0); 149 | } 150 | 151 | foreach(var _node in dialogs[nodeName].Right){ 152 | nodeName = _node; 153 | ConnectNode(graphEdit); 154 | } 155 | 156 | 157 | 158 | } 159 | 160 | public void AddNode(string filePath,GraphEdit graphEdit){ 161 | 162 | if(dialogs ==null) 163 | dialogs = resolver.ParseFile(filePath); 164 | characterNames = resolver.GetCharacters(filePath); 165 | 166 | if(visited.ContainsKey(nodeName)) 167 | return; 168 | else 169 | visited.Add(nodeName,true); 170 | 171 | 172 | if (nodeName.StartsWith("START")){ 173 | GraphNode node = (GraphNode)startNode.Instantiate(); 174 | node.Name = nodeName; 175 | node.Title = nodeName; 176 | Label dialogName= (Label)node.GetNode("HBoxContainer/Label"); 177 | dialogName.Text = Path.GetFileNameWithoutExtension(filePath); 178 | node.PositionOffset = position; 179 | position.X +=300; 180 | graphEdit.AddChild(node); 181 | 182 | }else if(nodeName.StartsWith("Dialog")){ 183 | GraphNode node = (GraphNode)dialogNode.Instantiate(); 184 | node.Name = nodeName; 185 | node.Title = nodeName; 186 | TextEdit contentEditor = node.GetNode("HFlowContainer/VBoxContainer/DialogContext/VBoxContainer/TextEdit"); 187 | OptionButton characterNameEditor = node.GetNode("HFlowContainer/HBoxContainer/OptionButton"); 188 | contentEditor.Text = dialogs[nodeName].Content; 189 | foreach (var (item, index) in characterNames.Select((value, i) => (value, i))){ 190 | characterNameEditor.AddItem(item); 191 | 192 | } 193 | characterNameEditor.Select(characterNames.IndexOf(dialogs[nodeName].Character)); 194 | 195 | if(dialogs[nodeName].Left.Count != 0){ 196 | GraphNode fatherNode =(GraphNode) graphEdit.GetNode( dialogs[nodeName].Left[0]); 197 | node.PositionOffset = new Vector2(fatherNode.PositionOffset.X+500,fatherNode.PositionOffset.Y+(dialogs[fatherNode.Name].Right.IndexOf(nodeName))*300); 198 | 199 | 200 | } 201 | 202 | graphEdit.AddChild(node); 203 | 204 | }else if(nodeName.StartsWith("Mutiple")){ 205 | GraphNode node = (GraphNode)mutipleNode.Instantiate(); 206 | node.Name = nodeName; 207 | node.Title = nodeName; 208 | OptionButton characterNameEditor = node.GetNode("VBoxContainer/HBoxContainer/OptionButton"); 209 | foreach (var (item, index) in characterNames.Select((value, i) => (value, i))){ 210 | characterNameEditor.AddItem(item); 211 | } 212 | characterNameEditor.Select(characterNames.IndexOf(dialogs[nodeName].Character)); 213 | 214 | foreach(var content in dialogs[nodeName].Selections){ 215 | HBoxContainer container = (HBoxContainer) itemNode.Instantiate(); 216 | container.Name = nodeName; 217 | TextEdit textEdit = (TextEdit) container.GetNode("TextEdit"); 218 | textEdit.Text = content; 219 | node.GetNode("VBoxContainer/ItemContainer").AddChild(container); 220 | 221 | 222 | 223 | } 224 | 225 | 226 | 227 | 228 | 229 | 230 | if(dialogs[nodeName].Left.Count != 0){ 231 | GraphNode fatherNode =(GraphNode) graphEdit.GetNode( dialogs[nodeName].Left[0]); 232 | node.PositionOffset = new Vector2(fatherNode.PositionOffset.X+500,fatherNode.PositionOffset.Y+(dialogs[fatherNode.Name].Right.IndexOf(nodeName))*300); 233 | 234 | 235 | } 236 | 237 | graphEdit.AddChild(node); 238 | 239 | } 240 | 241 | 242 | 243 | else if(nodeName.StartsWith("END")){ 244 | GraphNode node = (GraphNode)endNode.Instantiate(); 245 | node.Name = nodeName; 246 | node.Title = nodeName; 247 | node.PositionOffset = position; 248 | if(dialogs[nodeName].Left.Count != 0){ 249 | GraphNode fatherNode =(GraphNode) graphEdit.GetNode( dialogs[nodeName].Left[0]); 250 | node.PositionOffset = new Vector2(fatherNode.PositionOffset.X+500,fatherNode.PositionOffset.Y); 251 | 252 | } 253 | 254 | 255 | graphEdit.AddChild(node); 256 | 257 | } 258 | 259 | foreach(var _node in dialogs[nodeName].Right){ 260 | 261 | 262 | nodeName = _node; 263 | FileToGraph(filePath,graphEdit); 264 | 265 | } 266 | 267 | 268 | 269 | 270 | 271 | 272 | } 273 | 274 | public void FileToGraph(string filePath,GraphEdit graphEdit){ 275 | AddNode(filePath,graphEdit); 276 | nodeName = "START"; 277 | ConnectNode(graphEdit); 278 | 279 | 280 | 281 | 282 | } 283 | } 284 | --------------------------------------------------------------------------------