diff --git a/addons/LevelEditor/Draggable.gd b/addons/LevelEditor/Draggable.gd new file mode 100644 index 0000000..61510e1 --- /dev/null +++ b/addons/LevelEditor/Draggable.gd @@ -0,0 +1 @@ +extends Node diff --git a/addons/LevelEditor/Draggable.gd.uid b/addons/LevelEditor/Draggable.gd.uid new file mode 100644 index 0000000..2c4138e --- /dev/null +++ b/addons/LevelEditor/Draggable.gd.uid @@ -0,0 +1 @@ +uid://dno7nph2s6ad0 diff --git a/addons/LevelEditor/LevelEditor.gd b/addons/LevelEditor/LevelEditor.gd new file mode 100644 index 0000000..e5e1911 --- /dev/null +++ b/addons/LevelEditor/LevelEditor.gd @@ -0,0 +1,32 @@ +@tool +extends EditorPlugin + +# Replace this value with a PascalCase autoload name, as per the GDScript style guide. +#const AUTOLOAD_NAME = "LevelEditorAutoload" +const ui = preload("res://addons/LevelEditor/wave_maker.tscn") + +var main_panel_instance + +func _enter_tree(): + main_panel_instance = ui.instantiate() + # Add the main panel to the editor's main viewport. + EditorInterface.get_editor_main_screen().add_child(main_panel_instance) + # Hide the main panel. Very much required. + _make_visible(false) + + +func _has_main_screen(): + return true + + +func _make_visible(visible): + if main_panel_instance: + main_panel_instance.visible = visible + + +func _get_plugin_name(): + return "Level Editor" + + +func _get_plugin_icon(): + return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons") diff --git a/addons/LevelEditor/LevelEditor.gd.uid b/addons/LevelEditor/LevelEditor.gd.uid new file mode 100644 index 0000000..e1d9cb0 --- /dev/null +++ b/addons/LevelEditor/LevelEditor.gd.uid @@ -0,0 +1 @@ +uid://ppf3jmjydns0 diff --git a/addons/LevelEditor/UI/CustomLineEdit.gd b/addons/LevelEditor/UI/CustomLineEdit.gd new file mode 100644 index 0000000..69edbdf --- /dev/null +++ b/addons/LevelEditor/UI/CustomLineEdit.gd @@ -0,0 +1,51 @@ +@tool +extends LineEdit + +class_name CustomLineEdit + +enum TYPE { INT, TEXT, FLOAT } + +@export var inputType : TYPE +@export var step : float = 1 +var oldValue : String = "" + +var value: + get: + return getTypedValue(text) + +func _init() -> void: + text_changed.connect(valueUpdated) + + +func _input(event : InputEvent) -> void: + if !has_focus() || event is not InputEventKey || !event.pressed: + return + + processKeyInput(event) + + +func processKeyInput(event : InputEventKey) -> void: + if inputType in [TYPE.INT, TYPE.FLOAT]: + if event.keycode == KEY_UP: + text = str(getTypedValue(str(value + step))) + valueUpdated(text) + elif event.keycode == KEY_DOWN: + text = str(getTypedValue(str(value - step))) + valueUpdated(text) + + +func valueUpdated(newText : String) -> void: + valueHasChanged.emit(value) + + +func setValue(value) -> void: + text = str(getTypedValue(str(value))) + + +func getTypedValue(valueToType: String): + match inputType: + TYPE.INT: return int(valueToType) + TYPE.FLOAT: return float(valueToType) + _: return valueToType + +signal valueHasChanged(newValue) diff --git a/addons/LevelEditor/UI/CustomLineEdit.gd.uid b/addons/LevelEditor/UI/CustomLineEdit.gd.uid new file mode 100644 index 0000000..740a6f2 --- /dev/null +++ b/addons/LevelEditor/UI/CustomLineEdit.gd.uid @@ -0,0 +1 @@ +uid://bpv75ucqoy446 diff --git a/addons/LevelEditor/UI/CustomOptionButton.gd b/addons/LevelEditor/UI/CustomOptionButton.gd new file mode 100644 index 0000000..a5fdbe7 --- /dev/null +++ b/addons/LevelEditor/UI/CustomOptionButton.gd @@ -0,0 +1,47 @@ +@tool +extends OptionButton +class_name CustomOptionButton + +@export_dir var resourcePath : String +@export var regexPattern : String +@export var reloadOnOpen : bool = false + +var selectedValue : String + +func _ready() -> void: + loadData(true) + item_selected.connect(itemHasBeenSelected) + pressed.connect(loadData) + allow_reselect = true + +func loadData(force : bool = false) -> void: + if !force && !reloadOnOpen: + return + + var regex := RegEx.create_from_string(regexPattern) + var dir := DirAccess.open(resourcePath) + clear() + for file in dir.get_files(): + var fileMatch := regex.search(file) + if fileMatch: + add_item(fileMatch.strings[1]) + if selectedValue == fileMatch.strings[1]: + selected = item_count - 1 + + if !selectedValue && item_count > 0: + selected = 0 + +func itemHasBeenSelected(index : int) -> void: + if selectedValue != get_item_text(index): + selectedValue = get_item_text(index) + onValueChanged.emit(selectedValue) + + +func selectItemByName(name : String) -> void: + for i in item_count: + if get_item_text(i) == name: + selected = i + return + + +signal onValueChanged(value : String) diff --git a/addons/LevelEditor/UI/CustomOptionButton.gd.uid b/addons/LevelEditor/UI/CustomOptionButton.gd.uid new file mode 100644 index 0000000..690e15b --- /dev/null +++ b/addons/LevelEditor/UI/CustomOptionButton.gd.uid @@ -0,0 +1 @@ +uid://b47p2u458hsn0 diff --git a/addons/LevelEditor/UI/baseLabel.tres b/addons/LevelEditor/UI/baseLabel.tres new file mode 100644 index 0000000..9de60ce --- /dev/null +++ b/addons/LevelEditor/UI/baseLabel.tres @@ -0,0 +1,7 @@ +[gd_resource type="LabelSettings" load_steps=2 format=3 uid="uid://s1lfc81j20la"] + +[ext_resource type="FontFile" uid="uid://dv7ow5e7jj355" path="res://Assets/Fonts/Grandstander/static/Grandstander-Light.ttf" id="1_r6cgw"] + +[resource] +font = ExtResource("1_r6cgw") +font_size = 24 diff --git a/addons/LevelEditor/UI/theme.tres b/addons/LevelEditor/UI/theme.tres new file mode 100644 index 0000000..c698a00 --- /dev/null +++ b/addons/LevelEditor/UI/theme.tres @@ -0,0 +1,4 @@ +[gd_resource type="Theme" format=3 uid="uid://bvji8e8p2d72y"] + +[resource] +default_font_size = 20 diff --git a/addons/LevelEditor/UI/troopLabel.tres b/addons/LevelEditor/UI/troopLabel.tres new file mode 100644 index 0000000..1c450a9 --- /dev/null +++ b/addons/LevelEditor/UI/troopLabel.tres @@ -0,0 +1,7 @@ +[gd_resource type="LabelSettings" load_steps=2 format=3 uid="uid://bee458c1kc0j7"] + +[ext_resource type="FontFile" uid="uid://ctmfgwv1dwdyg" path="res://Assets/Fonts/Grandstander/static/Grandstander-BoldItalic.ttf" id="1_kyxue"] + +[resource] +font = ExtResource("1_kyxue") +font_size = 24 diff --git a/addons/LevelEditor/UI/waveLabel.tres b/addons/LevelEditor/UI/waveLabel.tres new file mode 100644 index 0000000..1d5577e --- /dev/null +++ b/addons/LevelEditor/UI/waveLabel.tres @@ -0,0 +1,7 @@ +[gd_resource type="LabelSettings" load_steps=2 format=3 uid="uid://cafoo04y1t31t"] + +[ext_resource type="FontFile" uid="uid://byqqml5g6dwil" path="res://Assets/Fonts/Grandstander/static/Grandstander-BlackItalic.ttf" id="1_m52f8"] + +[resource] +font = ExtResource("1_m52f8") +font_size = 32 diff --git a/addons/LevelEditor/WaveMaker.gd b/addons/LevelEditor/WaveMaker.gd new file mode 100644 index 0000000..633f682 --- /dev/null +++ b/addons/LevelEditor/WaveMaker.gd @@ -0,0 +1,237 @@ +@tool +extends Control + +const LEVEL_PATH : String = "res://Levels" +const LEVEL_NAME_PATERN : String = "level_{id}.tres" +const LEVEL_NAME_PATH_PATERN : String = LEVEL_PATH + "/{name}.tres" + +const ENEMY_PATH : String = "res://enemies" +const ENEMY_REGEX_PATERN : String = "(enemy.*)\\.tscn" + +const BASE_LABEL_SETTINGS = preload("res://addons/LevelEditor/UI/baseLabel.tres") +const WAVE_LABEL_SETTINGS = preload("res://addons/LevelEditor/UI/waveLabel.tres") +const TROOP_LABEL_SETTINGS = preload("res://addons/LevelEditor/UI/troopLabel.tres") + +const space_multiplicator : int = 10 +enum DIRECTION { UP, DOWN, TOP, LEFT, VERTICAL, HORIZONTAL} + + +@onready var autoLaunchLevel := $VBoxContainer2/ButtonContainer2/AutoLaunchLevel +@onready var levelSelect := $VBoxContainer2/HBoxContainer/LevelSelect +@onready var waveTabContainer := $VBoxContainer2/ScrollContainer/WaveContainer +@onready var waveTimerInput := $VBoxContainer2/ButtonContainer3/WaveTimer +var level : Level +var currentWave : int = -1 + + +func _input(event: InputEvent) -> void: + if !has_focus() || event is not InputEventKey || !event.pressed: + return + + if event.keycode == KEY_RIGHT && waveTabContainer.get_tab_count() > waveTabContainer.current_tab: + waveTabContainer.current_tab += 1 + elif event.keycode == KEY_LEFT && waveTabContainer.current_tab > 0: + waveTabContainer.current_tab -= 1 + + +func buildTree() -> void: + if !level: + return + + autoLaunchLevel.button_pressed = level.auto_start + for i in level.waves.size(): + var troopContainer := VBoxContainer.new() + buildWave(level.waves[i], troopContainer) + waveTabContainer.add_child(troopContainer) + waveTabContainer.set_tab_title(i, "Vague N°" + str(i + 1)) + + +func buildWave(wave : Wave, troopContainer : VBoxContainer) -> void: + for i in wave.troops.size(): + var troop : Troop = wave.troops[i] + + if i > 0 && !troopContainer.get_child(troopContainer.get_child_count() - 1).has_meta("troop_group") \ + || troop.spawn_delay > 0: + troopContainer.add_child(HSeparator.new()) + + if troop.spawn_delay: + var timeSeparator := buildInputLabel( + func(newValue): + troop.spawn_delay = newValue + if newValue == 0: + cleanAndBuildMenu(), + troop.spawn_delay, + CustomLineEdit.TYPE.FLOAT, + "sec." + ) + troopContainer.add_child(timeSeparator) + + var nodeToAppend : BoxContainer = troopContainer + if i < wave.troops.size() -1 && wave.troops[i + 1].spawn_delay == 0: + if i == 0 || !troopContainer.get_child(troopContainer.get_child_count() - 1).has_meta("troop_group"): + nodeToAppend = HBoxContainer.new() + nodeToAppend.size_flags_horizontal = Control.SIZE_SHRINK_CENTER + nodeToAppend.set_meta("troop_group", true) + troopContainer.add_child(nodeToAppend) + + if i > 0 && troop.spawn_delay == 0: + nodeToAppend = troopContainer.get_child(troopContainer.get_child_count() - 1) + nodeToAppend.add_child(VSeparator.new()) + + var ennemyContainer := VBoxContainer.new() + ennemyContainer.add_child(createSection("Troop N°" + str(i + 1), removeTroop.bind(troop, wave), TROOP_LABEL_SETTINGS)) + + if troop.spawn_delay == 0: + var button := Button.new() + button.text = "Séparer" + button.pressed.connect( + func(): + troop.spawn_delay = 1 + cleanAndBuildMenu() + ) + ennemyContainer.add_child(button) + + buildTroop(troop, ennemyContainer) + nodeToAppend.add_child(ennemyContainer) + + var addTroopBtn := Button.new() + addTroopBtn.text = "Ajouter une troupe" + addTroopBtn.pressed.connect(addTroop.bind(wave)) + troopContainer.add_child(addTroopBtn) + + + +func buildTroop(troop : Troop, ennemyContainer : VBoxContainer) -> void: + var qtyEdit := buildInputLabel( + func(newValue): troop.number_to_spawn = newValue, + troop.number_to_spawn, + CustomLineEdit.TYPE.INT, + "x" + ) + + var enemySelector := CustomOptionButton.new() + enemySelector.resourcePath = ENEMY_PATH + enemySelector.regexPattern = ENEMY_REGEX_PATERN + var regex = RegEx.create_from_string(ENEMY_REGEX_PATERN) + enemySelector.onValueChanged.connect(func(enemyFileName): addEnemy(troop, enemyFileName)) + if troop.enemy: + enemySelector.selectItemByName(regex.search(troop.enemy.resource_path).strings[0]) + + qtyEdit.add_child(enemySelector) + ennemyContainer.add_child(qtyEdit) + + +func buildInputLabel(updateCallback : Callable, delay : float, type : CustomLineEdit.TYPE, text : String = "") -> HBoxContainer: + var container := HBoxContainer.new() + container.size_flags_vertical = Control.SIZE_SHRINK_CENTER + container.alignment = BoxContainer.ALIGNMENT_CENTER + + var timeEdit := CustomLineEdit.new() + timeEdit.inputType = type + timeEdit.setValue(delay) + timeEdit.valueHasChanged.connect(updateCallback) + container.add_child(timeEdit) + + if text: + var label := Label.new() + label.text = text + label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + label.label_settings = BASE_LABEL_SETTINGS + container.add_child(label) + + return container + +func createSection(sectionName : String, BtnCallback : Callable, settings : LabelSettings = BASE_LABEL_SETTINGS) -> HSplitContainer : + var container := HSplitContainer.new() + + var label := Label.new() + label.text = sectionName + label.label_settings = settings + + var button := Button.new() + button.text = "Supprimer" + button.pressed.connect(BtnCallback) + + container.add_child(label) + container.add_child(button) + + return container + + +func cleanMenu() -> void: + if waveTabContainer.get_child_count() > 0: + for child in waveTabContainer.get_children(): + child.queue_free() + + +func removeWave() -> void: + level.waves.remove_at(currentWave) + waveTabContainer.get_child(currentWave).queue_free() + + +func addWave() -> void: + level.waves.append(Wave.new()) + cleanAndBuildMenu() + + +func changeWaveOrder(newPos : int) -> void: + var newWaveOrder : Array[Wave] + var waveToMove = level.waves[currentWave] + for i in level.waves.size(): + if i == 0 && newPos == 0: + newWaveOrder.append(waveToMove) + if i != currentWave: + newWaveOrder.append(level.waves[i]) + if i == newPos && newPos != 0: + newWaveOrder.append(waveToMove) + currentWave = newPos + level.waves = newWaveOrder + + + +func addTroop(toWave : Wave) -> void: + toWave.troops.append(Troop.new()) + cleanAndBuildMenu() + + +func addEnemy(toTroop : Troop, enemyResourcePath : String) -> void: + var enemy = load(enemyResourcePath) + toTroop.enemy = enemy + + +func removeTroop(troop : Troop, fromWave : Wave) -> void: + fromWave.troops.erase(troop) + cleanAndBuildMenu() + + +func selectLevel(levelName : String) -> void : + level = load(LEVEL_NAME_PATH_PATERN.format([["name", levelName]])) + + +func changeWaveCooldown(duration : float) -> void: + level.waves[currentWave].wait_time_before_launch_wave = duration + + +func tabFocusHaschanged(idx : int) -> void: + waveTimerInput.setValue(level.waves[idx].wait_time_before_launch_wave) + currentWave = idx + + +func cleanAndBuildMenu() -> void: + cleanMenu() + buildTree() + + +func _on_auto_launch_wave_toggled(toggled_on: bool) -> void: + level.auto_start = toggled_on + + +func _on_new_level_pressed() -> void: + level = Level.new() + levelSelect.add_item(LEVEL_NAME_PATERN.format([["id", levelSelect.item_count + 1]])) + levelSelect.select(levelSelect.item_count - 1) + _on_save_pressed() + + +func _on_save_pressed() -> void: + ResourceSaver.save(level, LEVEL_PATH + "/" + levelSelect.selectedValue, ResourceSaver.FLAG_BUNDLE_RESOURCES) diff --git a/addons/LevelEditor/WaveMaker.gd.uid b/addons/LevelEditor/WaveMaker.gd.uid new file mode 100644 index 0000000..26ef6d4 --- /dev/null +++ b/addons/LevelEditor/WaveMaker.gd.uid @@ -0,0 +1 @@ +uid://27y0jliv6ckx diff --git a/addons/LevelEditor/plugin.cfg b/addons/LevelEditor/plugin.cfg new file mode 100644 index 0000000..407f1c2 --- /dev/null +++ b/addons/LevelEditor/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="LevelEditor" +description="" +author="Varylios" +version="0.3" +script="LevelEditor.gd" diff --git a/addons/LevelEditor/wave_maker.tscn b/addons/LevelEditor/wave_maker.tscn new file mode 100644 index 0000000..7114cd3 --- /dev/null +++ b/addons/LevelEditor/wave_maker.tscn @@ -0,0 +1,132 @@ +[gd_scene load_steps=4 format=3 uid="uid://dh24t8804isms"] + +[ext_resource type="Script" uid="uid://27y0jliv6ckx" path="res://addons/LevelEditor/WaveMaker.gd" id="1_usfft"] +[ext_resource type="Script" uid="uid://b47p2u458hsn0" path="res://addons/LevelEditor/UI/CustomOptionButton.gd" id="2_xjxpq"] +[ext_resource type="Script" uid="uid://bpv75ucqoy446" path="res://addons/LevelEditor/UI/CustomLineEdit.gd" id="3_qw7ts"] + +[node name="Menu" type="HBoxContainer"] +offset_right = 885.0 +offset_bottom = 574.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource("1_usfft") + +[node name="MarginContainer" type="MarginContainer" parent="."] +custom_minimum_size = Vector2(20, 0) +layout_mode = 2 + +[node name="VBoxContainer2" type="VBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer2"] +custom_minimum_size = Vector2(0, 20) +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer2"] +layout_mode = 2 + +[node name="LevelSelect" type="OptionButton" parent="VBoxContainer2/HBoxContainer"] +layout_mode = 2 +selected = 0 +item_count = 2 +popup/item_0/text = "level_1" +popup/item_0/id = 0 +popup/item_1/text = "level_2" +popup/item_1/id = 1 +script = ExtResource("2_xjxpq") +resourcePath = "res://Levels" +regexPattern = "(level_.*)\\.tres" +reloadOnOpen = true +metadata/_custom_type_script = "uid://b47p2u458hsn0" + +[node name="NewLevel" type="Button" parent="VBoxContainer2/HBoxContainer"] +layout_mode = 2 +text = "Nouveau Niveau" + +[node name="Show" type="Button" parent="VBoxContainer2/HBoxContainer"] +layout_mode = 2 +text = "Afficher" + +[node name="Clean" type="Button" parent="VBoxContainer2/HBoxContainer"] +layout_mode = 2 +text = "Effacer" + +[node name="Save" type="Button" parent="VBoxContainer2/HBoxContainer"] +layout_mode = 2 +text = "Sauvegarder" + +[node name="Test" type="Button" parent="VBoxContainer2/HBoxContainer"] +visible = false +layout_mode = 2 +text = "TESTER !!!!" + +[node name="ButtonContainer" type="HBoxContainer" parent="VBoxContainer2"] +layout_mode = 2 + +[node name="Add wave" type="Button" parent="VBoxContainer2/ButtonContainer"] +layout_mode = 2 +text = "Ajouter une vague" + +[node name="ButtonContainer2" type="HBoxContainer" parent="VBoxContainer2"] +layout_mode = 2 + +[node name="AutoLaunchLevel" type="CheckButton" parent="VBoxContainer2/ButtonContainer2"] +layout_mode = 2 + +[node name="Label" type="Label" parent="VBoxContainer2/ButtonContainer2"] +layout_mode = 2 +text = "Lancer le niveau auto. " + +[node name="MarginContainer2" type="MarginContainer" parent="VBoxContainer2/ButtonContainer2"] +custom_minimum_size = Vector2(20, 0) +layout_mode = 2 + +[node name="RemoveWave" type="Button" parent="VBoxContainer2/ButtonContainer2"] +layout_mode = 2 +text = "Suprimer la vague" + +[node name="ButtonContainer3" type="HBoxContainer" parent="VBoxContainer2"] +layout_mode = 2 + +[node name="WaveTimer" type="LineEdit" parent="VBoxContainer2/ButtonContainer3"] +custom_minimum_size = Vector2(55, 55) +layout_mode = 2 +script = ExtResource("3_qw7ts") +inputType = 2 +step = 0.2 +metadata/_custom_type_script = "uid://bpv75ucqoy446" + +[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer2/ButtonContainer3"] +custom_minimum_size = Vector2(10, 0) +layout_mode = 2 + +[node name="Label" type="Label" parent="VBoxContainer2/ButtonContainer3"] +layout_mode = 2 +text = "Timer avant lancement de la vague" + +[node name="MarginContainer2" type="MarginContainer" parent="VBoxContainer2"] +custom_minimum_size = Vector2(0, 30) +layout_mode = 2 + +[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer2"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="WaveContainer" type="TabContainer" parent="VBoxContainer2/ScrollContainer"] +layout_mode = 2 +size_flags_vertical = 3 +clip_tabs = false +drag_to_rearrange_enabled = true + +[connection signal="onValueChanged" from="VBoxContainer2/HBoxContainer/LevelSelect" to="." method="selectLevel"] +[connection signal="pressed" from="VBoxContainer2/HBoxContainer/NewLevel" to="." method="_on_new_level_pressed"] +[connection signal="pressed" from="VBoxContainer2/HBoxContainer/Show" to="." method="cleanAndBuildMenu"] +[connection signal="pressed" from="VBoxContainer2/HBoxContainer/Clean" to="." method="cleanMenu"] +[connection signal="pressed" from="VBoxContainer2/HBoxContainer/Save" to="." method="_on_save_pressed"] +[connection signal="pressed" from="VBoxContainer2/ButtonContainer/Add wave" to="." method="addWave"] +[connection signal="toggled" from="VBoxContainer2/ButtonContainer2/AutoLaunchLevel" to="." method="_on_auto_launch_wave_toggled"] +[connection signal="pressed" from="VBoxContainer2/ButtonContainer2/RemoveWave" to="." method="removeWave"] +[connection signal="valueHasChanged" from="VBoxContainer2/ButtonContainer3/WaveTimer" to="." method="changeWaveCooldown"] +[connection signal="active_tab_rearranged" from="VBoxContainer2/ScrollContainer/WaveContainer" to="." method="changeWaveOrder"] +[connection signal="tab_changed" from="VBoxContainer2/ScrollContainer/WaveContainer" to="." method="tabFocusHaschanged"] diff --git a/addons/signal_lens/editor/signal_lens_editor_panel.gd b/addons/signal_lens/editor/signal_lens_editor_panel.gd index 1e5908c..fbda55e 100644 --- a/addons/signal_lens/editor/signal_lens_editor_panel.gd +++ b/addons/signal_lens/editor/signal_lens_editor_panel.gd @@ -17,7 +17,7 @@ const DEFAULT_EMISSION_DURATION: float = 1.0 ## TODO: This could be a user setting const DEFAULT_CONNECTION_OPACITY: float = 0.3 -## This enum is used to set up the graph node's ports +## This enum is used to set up the graph node's ports ## in a way that provides more legibility in the code enum Direction {LEFT, RIGHT} @@ -42,7 +42,7 @@ var block_new_inspections: bool = false ## If true, all incoming signal emissions will be drawn and won't fade out var keep_emissions: bool = false -## Multiplier that increases or decreases emission drawing speed +## Multiplier that increases or decreases emission drawing speed ## Acquired from slider in scene var emission_speed_multiplier: float = 1.0 @@ -61,10 +61,10 @@ var settings: Dictionary = { } # Scene references -@export var graph_edit: GraphEdit +@export var graph_edit: GraphEdit @export var logger_button: Button -@export var node_path_line_edit: LineEdit -@export var refresh_button: Button +@export var node_path_line_edit: LineEdit +@export var refresh_button: Button @export var options_button: MenuButton @onready var options_popup: PopupMenu = options_button.get_popup() @export var clear_button: Button @@ -96,7 +96,7 @@ func _ready() -> void: graph_edit.get_menu_hbox().hide() #graph_edit.get_menu_hbox().hide() repo_button.icon = EditorInterface.get_base_control().get_theme_icon("ExternalLink", "EditorIcons") - + @onready var repo_button: Button = $EditorPanel/MainButtonsContainer/HBoxContainer2/RepoButton @onready var panel_container: PanelContainer = $EditorPanel/PanelContainer @@ -143,13 +143,13 @@ func stop_session(): func assign_node_path(target_node: NodePath): # If locked button is toggled, don't change the current node if block_new_inspections: return - + # If incoming node is invalid, disable refreshing to avoid null nodes refresh_button.disabled = target_node.is_empty() - + # Assign incoming node as the current one current_node = target_node - + # Update line edit node_path_line_edit.text = current_node node_path_line_edit.caret_column = node_path_line_edit.text.length() @@ -167,7 +167,7 @@ func clear_graph(): clean_connection_activity() # Frees child nodes for child: Node in graph_edit.get_children(): - # This seems to be necessary as per Godot 4.3 + # This seems to be necessary as per Godot 4.3 # because this child, despite being internal, # is iterated in get_children() and if it is # destroyed, the editor crashed @@ -187,20 +187,20 @@ func clear_graph(): func draw_node_data(data: Array): # If lock button toggled on, don't draw incoming data if block_new_inspections: return - + # Clear graph to avoid drawing over old data clear_graph() logger.clear() - + # This line is super important to avoid random rendering errors # It seems we need to give a small breathing room for the graph edit # to fully cleanup, otherwise, artifacts from a previously rendered # graph edit may appear and mess up the new drawing await get_tree().create_timer(0.1).timeout - + # Retrieve the targeted node from the data array, which is always index 0 var target_node_name = data[0] - + # Handle root node inspection edge case if target_node_name == "Root": warning_text.show() @@ -211,19 +211,19 @@ func draw_node_data(data: Array): # Retrieve the targeted node signal data, which is always index 1 var target_node_signal_data: Array = data[1] - + # Create main node from which connections will be created # and add it to the graph var target_node: SignalLensGraphNode = create_node(target_node_name, "(Signals)") graph_edit.add_child(target_node) - + var current_signal_index = 0 - + # Start iterating signal by signal for signal_data in target_node_signal_data: # Check signal connections and skip not connected signals (based on settings) if settings[Options.HIDE_SIGNALS_WITHOUT_CONNECTIONS] and signal_data["callables"].size() == 0: continue - + # Check signal connections and skip if signal is built-in (based on settings) if settings[Options.HIDE_BUILT_IN_SIGNALS]: var class_signals: Array = [] @@ -231,13 +231,13 @@ func draw_node_data(data: Array): class_signals.append(class_signal["name"]) if signal_data["signal"] in class_signals: continue - + # Get the color based on the index so we can have the rainbow vibes var slot_color = get_slot_color(current_signal_index, target_node_signal_data.size()) - + # Create the slot button with the signal's name create_button_slot(signal_data["signal"], target_node, Direction.RIGHT, slot_color) - + # Start iterating each callable in the signal var callables_for_current_signal = signal_data["callables"] for callable_index in range(callables_for_current_signal.size()): @@ -306,8 +306,8 @@ func create_button_slot(button_text: String, parent_node: GraphNode, slot_direct parent_node.set_slot(signal_button.get_index(), slot_direction == Direction.LEFT, 0, slot_color, slot_direction == Direction.RIGHT, 0, slot_color) func get_slot_color(slot_index, signal_amount) -> Color: - var hue = float(slot_index) / float(signal_amount) - return Color.from_hsv(hue, 1.0, 0.5, connection_opacity) + var hue = float(slot_index) / float(signal_amount) + return Color.from_hsv(hue, 1.0, 0.5, connection_opacity) func clean_connection_activity(): for connection in graph_edit.get_connection_list(): @@ -331,13 +331,13 @@ func draw_signal_emission(data: Array): func pulse_connection(connection: Dictionary) -> void: if connection not in pulsing_connections: pulsing_connections.append(connection) - + var from_node = connection["from_node"] var from_port = connection["from_port"] var to_node = connection["to_node"] var to_port = connection["to_port"] - - if keep_emissions: + + if keep_emissions: graph_edit.set_connection_activity(from_node, from_port, to_node, to_port, 1.0) else: fade_out_connection(connection) @@ -349,11 +349,11 @@ func fade_out_connection(connection: Dictionary): var from_port = connection["from_port"] var to_node = connection["to_node"] var to_port = connection["to_port"] - + tween.tween_method( func(value): graph_edit.set_connection_activity(from_node, from_port, to_node, to_port, value), 1.0, 0.0, fade_out_duration ).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN) - + tween.tween_callback(func(): pulsing_connections.erase(connection)) func get_port_index_from_signal_name(signal_name: String): @@ -407,7 +407,7 @@ func _resize_panel(new_size: float): func _can_resize_panel() -> bool: # If user wants to resize panel on open if not ProjectSettings.get_setting("addons/Signal Lens/resize_panel_on_open"): return false - + # If editor dock reference has been acquired if not _editor_dock: return false return true @@ -417,7 +417,7 @@ func _on_visibility_changed() -> void: # Only resize bottom panel if both visible and visible in editor if visible and is_visible_in_tree(): _resize_panel(-ProjectSettings.get_setting("addons/Signal Lens/height_to_resize_to")) - else: + else: _resize_panel(_original_panel_size) func _open_project_settings(): @@ -517,12 +517,12 @@ func _on_keep_emissions_checkbox_toggled(toggled_on: bool) -> void: func _on_logger_button_toggled(toggled_on: bool) -> void: logger.visible = toggled_on - + func _on_options_index_pressed(option_index: int) -> void: if options_popup.is_item_checkable(option_index): settings[option_index] = not options_popup.is_item_checked(option_index) # Change state options_popup.set_item_checked(option_index, settings[option_index]) # Apply state - + if option_index in [Options.HIDE_SIGNALS_WITHOUT_CONNECTIONS, Options.HIDE_BUILT_IN_SIGNALS]: refresh_button.pressed.emit() elif option_index == Options.SHOW_GRAPH_TOOLBAR: diff --git a/project.godot b/project.godot index f459e04..921a506 100644 --- a/project.godot +++ b/project.godot @@ -29,7 +29,7 @@ window/size/viewport_height=1080 [editor_plugins] -enabled=PackedStringArray("res://addons/signal_lens/plugin.cfg") +enabled=PackedStringArray("res://addons/LevelEditor/plugin.cfg", "res://addons/signal_lens/plugin.cfg") [file_customization]