└── addons └── event_system_plugin ├── LICENSE ├── assets ├── icons │ ├── event_icons │ │ ├── call.svg │ │ ├── call.svg.import │ │ ├── condition.svg │ │ ├── condition.svg.import │ │ ├── custom.svg │ │ ├── custom.svg.import │ │ ├── emit_signal.svg │ │ ├── emit_signal.svg.import │ │ ├── goto.svg │ │ ├── goto.svg.import │ │ ├── hidden.png │ │ ├── hidden.png.import │ │ ├── label.svg │ │ ├── label.svg.import │ │ ├── outline.svg │ │ ├── outline.svg.import │ │ ├── set_value.svg │ │ ├── set_value.svg.import │ │ ├── solid.svg │ │ ├── solid.svg.import │ │ ├── visible.png │ │ ├── visible.png.import │ │ ├── wait.svg │ │ └── wait.svg.import │ ├── timeline_icon.png │ ├── timeline_icon.png.import │ ├── warning.svg │ └── warning.svg.import └── themes │ ├── event_node │ └── event_node.tres │ ├── timeline_editor.tres │ └── timeline_editor │ └── timeline_editor_d.tres ├── core ├── event_inspector.gd ├── inspector_tools.gd ├── shortcuts.gd └── utils.gd ├── events ├── call_from.gd ├── comment.gd ├── condition.gd ├── emit_signal.gd ├── end_timeline.gd ├── goto.gd ├── hide.gd ├── set.gd ├── show.gd └── wait.gd ├── godot_plugin.gd ├── icon.png ├── icon.png.import ├── nodes ├── editor │ ├── category_manager.gd │ ├── event_node │ │ ├── event_condition_node.gd │ │ ├── event_node.gd │ │ └── event_popup_menu.gd │ ├── event_selector │ │ ├── event_selector.gd │ │ └── event_selector.tscn │ ├── flow_container.gd │ ├── playground │ │ ├── event_manager_demo.tscn │ │ └── in_game_editor.tscn │ ├── subtimeline.gd │ ├── timeline_displayer.gd │ ├── timeline_drawer.gd │ ├── timeline_editor.gd │ ├── timeline_list.gd │ └── welcome │ │ ├── main_panel.gd │ │ └── main_panel.tscn └── event_manager │ └── event_manager.gd ├── plugin.cfg ├── plugin_script.gd └── resources ├── event_class └── event_class.gd ├── registered_events ├── _.gd └── registered_events.tres └── timeline_class └── timeline_class.gd /addons/event_system_plugin/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 AnidemDex 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/call.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/call.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/call.svg-fcdd23d46a12116186f791edf9462815.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/event_system_plugin/assets/icons/event_icons/call.svg" 13 | dest_files=[ "res://.import/call.svg-fcdd23d46a12116186f791edf9462815.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/condition.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/condition.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/condition.svg-579187d50a8d87875312075e1a14293c.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/event_system_plugin/assets/icons/event_icons/condition.svg" 13 | dest_files=[ "res://.import/condition.svg-579187d50a8d87875312075e1a14293c.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/custom.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/custom.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/custom.svg-59e2fe8ffe62fc955b993462f3466265.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/event_system_plugin/assets/icons/event_icons/custom.svg" 13 | dest_files=[ "res://.import/custom.svg-59e2fe8ffe62fc955b993462f3466265.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/emit_signal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/emit_signal.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/emit_signal.svg-f1e8e658a5abcf471929727d8464bbbe.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/event_system_plugin/assets/icons/event_icons/emit_signal.svg" 13 | dest_files=[ "res://.import/emit_signal.svg-f1e8e658a5abcf471929727d8464bbbe.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/goto.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/goto.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/goto.svg-cf34756d48e0fa3017e79ddc4f206c33.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/event_system_plugin/assets/icons/event_icons/goto.svg" 13 | dest_files=[ "res://.import/goto.svg-cf34756d48e0fa3017e79ddc4f206c33.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/hidden.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:22c7cb90e975f2affe859327a0220059c4addb863bdaa846298dd11752c29393 3 | size 350 4 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/hidden.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/hidden.png-da303d5e7240bd64d6960f6154b2d56a.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/event_system_plugin/assets/icons/event_icons/hidden.png" 13 | dest_files=[ "res://.import/hidden.png-da303d5e7240bd64d6960f6154b2d56a.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/label.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/label.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/label.svg-04a81bdfdbc5fd4b90f6b68a75c0e04e.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/event_system_plugin/assets/icons/event_icons/label.svg" 13 | dest_files=[ "res://.import/label.svg-04a81bdfdbc5fd4b90f6b68a75c0e04e.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/outline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/outline.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/outline.svg-80b64523e937bd316725c9fce70a2da7.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/event_system_plugin/assets/icons/event_icons/outline.svg" 13 | dest_files=[ "res://.import/outline.svg-80b64523e937bd316725c9fce70a2da7.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/set_value.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/set_value.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/set_value.svg-96015dc53b42e43f938bbe0cb70a49c4.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/event_system_plugin/assets/icons/event_icons/set_value.svg" 13 | dest_files=[ "res://.import/set_value.svg-96015dc53b42e43f938bbe0cb70a49c4.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/solid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/solid.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/solid.svg-1e2db139c93da3bfad4b54110345d3c0.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/event_system_plugin/assets/icons/event_icons/solid.svg" 13 | dest_files=[ "res://.import/solid.svg-1e2db139c93da3bfad4b54110345d3c0.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/visible.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:298df18f88878a09d39cdcd0d7c217249b853a87781c92ac73cc1283a69be0f2 3 | size 364 4 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/visible.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/visible.png-538e566050bb4faf2b8f2c1eff052afe.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/event_system_plugin/assets/icons/event_icons/visible.png" 13 | dest_files=[ "res://.import/visible.png-538e566050bb4faf2b8f2c1eff052afe.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/wait.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/event_icons/wait.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/wait.svg-1fc38f1e456deb8d5521fdfa9f9c5133.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/event_system_plugin/assets/icons/event_icons/wait.svg" 13 | dest_files=[ "res://.import/wait.svg-1fc38f1e456deb8d5521fdfa9f9c5133.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/timeline_icon.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:140dca20a9c1784f1e0b854219ff913380ed5f73c5f1f2cf02af654ab8dca3c0 3 | size 173 4 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/timeline_icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/timeline_icon.png-18a80ece71c9c4e87e5312d030cdeba2.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/event_system_plugin/assets/icons/timeline_icon.png" 13 | dest_files=[ "res://.import/timeline_icon.png-18a80ece71c9c4e87e5312d030cdeba2.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/warning.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/icons/warning.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/warning.svg-8a96b0f48377176c4d03aea4fefa1c18.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/event_system_plugin/assets/icons/warning.svg" 13 | dest_files=[ "res://.import/warning.svg-8a96b0f48377176c4d03aea4fefa1c18.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/themes/event_node/event_node.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Theme" load_steps=6 format=2] 2 | 3 | [sub_resource type="StyleBoxEmpty" id=5] 4 | 5 | [sub_resource type="StyleBoxFlat" id=2] 6 | 7 | [sub_resource type="StyleBoxFlat" id=3] 8 | content_margin_left = 8.0 9 | content_margin_right = 4.0 10 | content_margin_top = 4.0 11 | content_margin_bottom = 4.0 12 | corner_radius_top_left = 32 13 | corner_radius_bottom_left = 32 14 | 15 | [sub_resource type="StyleBoxFlat" id=4] 16 | content_margin_left = 12.0 17 | content_margin_right = 8.0 18 | content_margin_top = 4.0 19 | content_margin_bottom = 4.0 20 | corner_radius_top_right = 32 21 | corner_radius_bottom_right = 32 22 | shadow_offset = Vector2( 2, 0 ) 23 | 24 | [sub_resource type="StyleBoxFlat" id=1] 25 | content_margin_left = 8.0 26 | content_margin_right = 8.0 27 | content_margin_top = 4.0 28 | content_margin_bottom = 4.0 29 | draw_center = false 30 | border_width_left = 2 31 | border_width_top = 2 32 | border_width_right = 2 33 | border_width_bottom = 2 34 | border_color = Color( 0.0980392, 0.113725, 0.156863, 1 ) 35 | corner_radius_top_left = 16 36 | corner_radius_top_right = 16 37 | corner_radius_bottom_right = 16 38 | corner_radius_bottom_left = 16 39 | 40 | [resource] 41 | Button/styles/disabled = SubResource( 5 ) 42 | Button/styles/focus = SubResource( 5 ) 43 | Button/styles/hover = SubResource( 5 ) 44 | Button/styles/normal = SubResource( 5 ) 45 | Button/styles/pressed = SubResource( 5 ) 46 | EventNode/colors/default = Color( 0.6, 0.6, 0.6, 1 ) 47 | EventNode/colors/event = Color( 0.984314, 0.694118, 0.235294, 1 ) 48 | EventNode/colors/hover = Color( 0.156863, 0.572549, 0.843137, 1 ) 49 | EventNode/colors/outline = Color( 0.0980392, 0.113725, 0.156863, 1 ) 50 | EventNode/styles/bg = SubResource( 2 ) 51 | EventNode/styles/bg_left = SubResource( 3 ) 52 | EventNode/styles/bg_right = SubResource( 4 ) 53 | EventNode/styles/outline = SubResource( 1 ) 54 | HBoxContainer/constants/separation = 0 55 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/themes/timeline_editor.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Theme" load_steps=19 format=2] 2 | 3 | [ext_resource path="res://addons/event_system_plugin/assets/icons/event_icons/outline.svg" type="Texture" id=1] 4 | [ext_resource path="res://addons/event_system_plugin/assets/icons/warning.svg" type="Texture" id=2] 5 | [ext_resource path="res://addons/event_system_plugin/assets/icons/event_icons/wait.svg" type="Texture" id=3] 6 | [ext_resource path="res://addons/event_system_plugin/assets/icons/event_icons/goto.svg" type="Texture" id=4] 7 | [ext_resource path="res://addons/event_system_plugin/assets/icons/event_icons/set_value.svg" type="Texture" id=5] 8 | [ext_resource path="res://addons/event_system_plugin/assets/icons/event_icons/emit_signal.svg" type="Texture" id=6] 9 | [ext_resource path="res://addons/event_system_plugin/assets/icons/event_icons/call.svg" type="Texture" id=7] 10 | [ext_resource path="res://addons/event_system_plugin/assets/icons/event_icons/condition.svg" type="Texture" id=9] 11 | [ext_resource path="res://addons/event_system_plugin/assets/icons/event_icons/label.svg" type="Texture" id=10] 12 | [ext_resource path="res://addons/event_system_plugin/assets/icons/event_icons/visible.png" type="Texture" id=11] 13 | [ext_resource path="res://addons/event_system_plugin/assets/icons/event_icons/hidden.png" type="Texture" id=12] 14 | 15 | [sub_resource type="StyleBoxFlat" id=6] 16 | bg_color = Color( 1, 1, 1, 1 ) 17 | border_width_left = 1 18 | border_width_top = 1 19 | border_width_right = 1 20 | border_width_bottom = 1 21 | border_color = Color( 1, 1, 1, 0 ) 22 | corner_radius_top_left = 4 23 | corner_radius_bottom_left = 4 24 | 25 | [sub_resource type="StyleBoxFlat" id=4] 26 | content_margin_right = 6.0 27 | draw_center = false 28 | border_width_left = 1 29 | border_width_top = 1 30 | border_width_right = 1 31 | border_width_bottom = 1 32 | border_color = Color( 0.0980392, 0.0980392, 0.0980392, 0.784314 ) 33 | corner_radius_top_left = 4 34 | corner_radius_top_right = 4 35 | corner_radius_bottom_right = 4 36 | corner_radius_bottom_left = 4 37 | 38 | [sub_resource type="StyleBoxFlat" id=9] 39 | content_margin_top = 4.0 40 | content_margin_bottom = 4.0 41 | bg_color = Color( 0.509804, 0.509804, 0.509804, 0.207843 ) 42 | border_color = Color( 1, 1, 1, 1 ) 43 | 44 | [sub_resource type="StyleBoxFlat" id=1] 45 | content_margin_left = 8.0 46 | content_margin_right = 8.0 47 | content_margin_top = 4.0 48 | content_margin_bottom = 4.0 49 | draw_center = false 50 | border_width_left = 2 51 | border_width_top = 2 52 | border_width_right = 2 53 | border_width_bottom = 2 54 | border_color = Color( 0.0980392, 0.113725, 0.156863, 1 ) 55 | corner_radius_top_left = 16 56 | corner_radius_top_right = 16 57 | corner_radius_bottom_right = 16 58 | corner_radius_bottom_left = 16 59 | 60 | [sub_resource type="StyleBoxFlat" id=10] 61 | bg_color = Color( 0.509804, 0.509804, 0.509804, 0.207843 ) 62 | border_width_left = 5 63 | border_color = Color( 1, 1, 1, 1 ) 64 | 65 | [sub_resource type="StyleBoxFlat" id=11] 66 | content_margin_left = 10.0 67 | content_margin_right = 10.0 68 | content_margin_top = 10.0 69 | content_margin_bottom = 10.0 70 | bg_color = Color( 0.2, 0.23, 0.31, 1 ) 71 | border_width_left = 1 72 | border_width_top = 1 73 | border_width_right = 1 74 | border_width_bottom = 1 75 | border_color = Color( 0.8, 0.8, 0.8, 0.109804 ) 76 | corner_radius_top_left = 4 77 | corner_radius_top_right = 4 78 | corner_radius_bottom_right = 4 79 | corner_radius_bottom_left = 4 80 | 81 | [sub_resource type="StyleBoxEmpty" id=7] 82 | 83 | [resource] 84 | EventButton/styles/border = SubResource( 6 ) 85 | EventButton/styles/normal = SubResource( 4 ) 86 | EventIcons/icons/call = ExtResource( 7 ) 87 | EventIcons/icons/comment = ExtResource( 10 ) 88 | EventIcons/icons/condition = ExtResource( 9 ) 89 | EventIcons/icons/custom = ExtResource( 2 ) 90 | EventIcons/icons/emit_signal = ExtResource( 6 ) 91 | EventIcons/icons/go_to = ExtResource( 4 ) 92 | EventIcons/icons/hide = ExtResource( 12 ) 93 | EventIcons/icons/set = ExtResource( 5 ) 94 | EventIcons/icons/show = ExtResource( 11 ) 95 | EventIcons/icons/wait = ExtResource( 3 ) 96 | EventNode/colors/default = Color( 0.6, 0.6, 0.6, 1 ) 97 | EventNode/colors/event = Color( 0.984314, 0.694118, 0.235294, 1 ) 98 | EventNode/colors/hover = Color( 0.156863, 0.572549, 0.843137, 1 ) 99 | EventNode/colors/outline = Color( 0.0980392, 0.113725, 0.156863, 1 ) 100 | EventNode/constants/indentation = 32 101 | EventNode/constants/margin_left = 6 102 | EventNode/icons/bg = ExtResource( 1 ) 103 | EventNode/icons/checked = null 104 | EventNode/icons/unchecked = null 105 | EventNode/styles/hover = SubResource( 9 ) 106 | EventNode/styles/outline = SubResource( 1 ) 107 | EventNode/styles/pressed = SubResource( 10 ) 108 | PopupMenu/styles/panel = SubResource( 11 ) 109 | ToolButton/styles/focus = SubResource( 7 ) 110 | VBoxContainer/constants/separation = 0 111 | -------------------------------------------------------------------------------- /addons/event_system_plugin/assets/themes/timeline_editor/timeline_editor_d.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Theme" load_steps=2 format=2] 2 | 3 | [sub_resource type="StyleBoxFlat" id=1] 4 | bg_color = Color( 0.14902, 0.172549, 0.231373, 1 ) 5 | border_width_left = 1 6 | border_width_top = 1 7 | border_width_right = 1 8 | border_width_bottom = 1 9 | border_color = Color( 0.0980392, 0.113725, 0.156863, 1 ) 10 | anti_aliasing = false 11 | 12 | [resource] 13 | ScrollContainer/styles/bg = SubResource( 1 ) 14 | -------------------------------------------------------------------------------- /addons/event_system_plugin/core/event_inspector.gd: -------------------------------------------------------------------------------- 1 | extends EditorInspectorPlugin 2 | 3 | const InspectorTools = preload("res://addons/event_system_plugin/core/inspector_tools.gd") 4 | 5 | class EventInfo extends VBoxContainer: 6 | func _init(): 7 | pass 8 | pass 9 | 10 | var EventClass = load("res://addons/event_system_plugin/resources/event_class/event_class.gd") 11 | 12 | var editor_gui:Control 13 | 14 | func can_handle(object: Object) -> bool: 15 | return object is EventClass 16 | 17 | 18 | func parse_category(object: Object, category: String) -> void: 19 | if category == "Script Variables": 20 | var category_node := InspectorTools.InspectorCategory.new() 21 | category_node.label = "Event [%s]"%str(object.get("event_name")) 22 | category_node.bg_color = object.get("event_color") as Color 23 | category_node.bg_color.a = 0.4 24 | category_node.hint_tooltip = object.get("event_hint") 25 | add_custom_control(category_node) 26 | 27 | var event_info 28 | 29 | 30 | func parse_property(object: Object, type: int, path: String, hint: int, hint_text: String, usage: int) -> bool: 31 | if object == null: 32 | return false 33 | var path_ignore = path+"_ignore" 34 | if (path_ignore in object): 35 | return true 36 | 37 | if path == "next_event": 38 | var node = InspectorTools.InspectorEventSelector.new() 39 | add_property_editor(path, node) 40 | return true 41 | 42 | return false 43 | -------------------------------------------------------------------------------- /addons/event_system_plugin/core/inspector_tools.gd: -------------------------------------------------------------------------------- 1 | tool 2 | 3 | class InspectorCategory extends Control: 4 | var icon:Texture 5 | var label:String 6 | var bg_color:Color = Color.black 7 | 8 | func _draw() -> void: 9 | draw_rect(Rect2(Vector2(), rect_size), bg_color) 10 | 11 | var font:Font = get_font("font", "Tree") 12 | 13 | var hs:int = get_constant("hseparation", "Tree"); 14 | var w:int = font.get_string_size(label).x; 15 | if (icon): 16 | w += hs + icon.get_width(); 17 | 18 | var ofs:int = (rect_size.x - w) / 2 19 | 20 | if (icon): 21 | draw_texture(icon, Vector2(ofs, (rect_size.y - icon.get_height()) / 2).floor()) 22 | ofs += hs + icon.get_width(); 23 | 24 | var color:Color = get_color("font_color", "Tree") 25 | draw_string(font, Vector2(ofs, font.get_ascent() + (rect_size.y - font.get_height()) / 2).floor(), label, color, rect_size.x); 26 | 27 | func _get_minimum_size() -> Vector2: 28 | var font:Font = get_font("font", "Tree") 29 | 30 | var ms:Vector2 = Vector2() 31 | ms.x = 1; 32 | ms.y = font.get_height() 33 | if icon: 34 | ms.y = max(icon.get_height(), ms.y); 35 | ms.y += get_constant("vseparation", "Tree"); 36 | 37 | return ms; 38 | 39 | func _ready() -> void: 40 | var parent = get_parent() 41 | if is_instance_valid(parent): 42 | if get_position_in_parent() != 0: 43 | var category := parent.get_child(get_position_in_parent()-1) as Control 44 | category.hide() 45 | 46 | if icon == null: 47 | icon = get_icon("Object", "EditorIcons") 48 | update() 49 | 50 | if bg_color == Color.black: 51 | bg_color = get_color("prop_category", "Editor") 52 | update() 53 | 54 | 55 | class InspectorEventSelector extends EditorProperty: 56 | var event_selector:Button 57 | var popup:ConfirmationDialog 58 | var reset_button:Button 59 | var info_label:Label 60 | var updating:bool = false 61 | func _init() -> void: 62 | event_selector = Button.new() 63 | event_selector.text = "Select event" 64 | event_selector.connect("pressed",self,"_on_button_pressed") 65 | event_selector.size_flags_horizontal = SIZE_EXPAND_FILL 66 | 67 | reset_button = Button.new() 68 | reset_button.connect("pressed", self, "_on_reset_pressed") 69 | 70 | var hb = HBoxContainer.new() 71 | add_child(hb) 72 | hb.add_child(event_selector) 73 | hb.add_child(reset_button) 74 | 75 | popup = load("res://addons/event_system_plugin/nodes/editor/event_selector/event_selector.tscn").instance() 76 | popup.connect("event_selected", self, "_on_event_selected") 77 | add_child(popup) 78 | 79 | info_label = Label.new() 80 | info_label.size_flags_horizontal = SIZE_EXPAND_FILL 81 | info_label.align = Label.ALIGN_RIGHT 82 | add_child(info_label) 83 | set_bottom_editor(info_label) 84 | 85 | 86 | func _ready(): 87 | reset_button.icon = get_icon("Remove", "EditorIcons") 88 | update_property() 89 | 90 | 91 | func update_property(): 92 | var data:Array = str(get_edited_object()[get_edited_property()]).split(";", false) 93 | if data.empty(): 94 | return 95 | 96 | var event_idx = data[0] 97 | var timeline_path = "" 98 | if data.size() >= 2: 99 | timeline_path = data[1] 100 | 101 | var timeline = null 102 | if timeline_path != "": 103 | var node = Engine.get_meta("EventSystem").timeline_editor._edited_node 104 | if is_instance_valid(node): 105 | timeline = node.get_timeline(timeline_path) 106 | 107 | if not timeline: 108 | timeline = Engine.get_meta("EventSystem").timeline_editor._edited_sequence 109 | 110 | if not timeline: 111 | return 112 | 113 | var event = timeline.get_event(int(event_idx)) 114 | updating = true 115 | 116 | if event: 117 | event_selector.text = event.get("event_name") 118 | else: 119 | event_selector.text = "Select event" 120 | 121 | info_label.text = "On timeline: '{name}'".format({"name":timeline_path}) 122 | 123 | updating = false 124 | 125 | 126 | func _on_button_pressed() -> void: 127 | var timeline = Engine.get_meta("EventSystem").timeline_editor._edited_sequence 128 | if timeline: 129 | popup.build_timeline(timeline) 130 | popup.call_deferred("popup_centered_ratio", 0.45) 131 | 132 | 133 | func _on_event_selected(event_idx, path) -> void: 134 | if updating: 135 | return 136 | var value = "{idx};{path}".format({"idx":event_idx, "path":path}) 137 | emit_changed(get_edited_property(), value) 138 | 139 | 140 | func _on_reset_pressed() -> void: 141 | if updating: 142 | return 143 | 144 | emit_changed(get_edited_property(), "-1;") 145 | -------------------------------------------------------------------------------- /addons/event_system_plugin/core/shortcuts.gd: -------------------------------------------------------------------------------- 1 | extends Reference 2 | 3 | static func get_shortcut(property: String) -> ShortCut: 4 | var shortcut:ShortCut = ShortCut.new() 5 | match property: 6 | "duplicate": 7 | shortcut = null 8 | if Engine.editor_hint: 9 | var plugin = ClassDB.instance("EditorPlugin") 10 | var settings:EditorSettings = plugin.get_editor_interface().get_editor_settings() 11 | # shortcut = settings.get("scene_tree/duplicate") as ShortCut 12 | shortcut = null # We can't get shortcuts for now 13 | plugin.free() 14 | 15 | if shortcut == null: 16 | shortcut = ShortCut.new() 17 | var input := InputEventKey.new() 18 | input.scancode = KEY_D 19 | input.control = true 20 | input.pressed = true 21 | shortcut.shortcut = input 22 | 23 | "remove","delete": 24 | shortcut = null 25 | 26 | if Engine.editor_hint: 27 | var plugin = ClassDB.instance("EditorPlugin") 28 | var settings:EditorSettings = plugin.get_editor_interface().get_editor_settings() 29 | # shortcut = settings.get("scene_tree/delete") as ShortCut 30 | shortcut = null # we can't get shortcuts for now 31 | plugin.free() 32 | 33 | if shortcut == null: 34 | shortcut = ShortCut.new() 35 | var input := InputEventKey.new() 36 | input.scancode = KEY_DELETE 37 | input.pressed = true 38 | shortcut.shortcut = input 39 | 40 | 41 | return shortcut 42 | -------------------------------------------------------------------------------- /addons/event_system_plugin/core/utils.gd: -------------------------------------------------------------------------------- 1 | extends Reference 2 | 3 | ## Util function to get a dictionary of object property:value 4 | static func get_property_values_from(object:Object) -> Dictionary: 5 | if object == null: 6 | return {} 7 | var dict = {} 8 | # Hope this doesn't freeze the engine per call 9 | for property in object.get_property_list(): 10 | dict[property.name] = object.get(property.name) 11 | return dict 12 | 13 | 14 | # Based on: https://www.askpython.com/python/built-in-methods/python-eval 15 | ## Evaluates an string, excecutes it and returns the result 16 | static func evaluate(input:String, global:Object=null, locals:Dictionary={}, _show_error:bool=true): 17 | var _evaluated_value = null 18 | var _expression = Expression.new() 19 | 20 | var _err = _expression.parse(input, PoolStringArray(locals.keys())) 21 | 22 | if _err != OK: 23 | push_warning(_expression.get_error_text()) 24 | else: 25 | _evaluated_value = _expression.execute(locals.values(), global, _show_error) 26 | 27 | if _expression.has_execute_failed(): 28 | return input 29 | 30 | return _evaluated_value 31 | -------------------------------------------------------------------------------- /addons/event_system_plugin/events/call_from.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Event 3 | class_name EventCall 4 | 5 | ## Makes a [code]call()[/code] to a method in a node with any number of arguments. 6 | 7 | export(String) var method:String = "" setget set_method 8 | export(Array) var args:Array = [] 9 | 10 | func _init() -> void: 11 | event_color = Color("EB5E55") 12 | event_name = "Call" 13 | event_category = "Node" 14 | event_preview_string = "{event_node_path} {method} ( {args} ) " 15 | 16 | args = [] 17 | 18 | 19 | func _execute() -> void: 20 | var node:Node = get_event_node() 21 | 22 | if node.has_method(method): 23 | node.callv(method, args) 24 | 25 | finish() 26 | 27 | 28 | func set_method(value:String) -> void: 29 | method = value 30 | emit_changed() 31 | property_list_changed_notify() 32 | 33 | 34 | func set_args(value:Array) -> void: 35 | args = value.duplicate() 36 | emit_changed() 37 | property_list_changed_notify() 38 | -------------------------------------------------------------------------------- /addons/event_system_plugin/events/comment.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Event 3 | class_name EventComment 4 | 5 | ## A single comment. 6 | ## It does nothing and can be used as a label point for Go To event. 7 | 8 | export(String, MULTILINE) var text:String = "" setget set_text 9 | 10 | func _init() -> void: 11 | event_name = "Comment" 12 | event_preview_string = "# {text}" 13 | event_hint = "Makes comment in the timeline.\nThis doesn't affects the timeline behaviour." 14 | event_color = Color("#3C3D5E") 15 | continue_at_end = true 16 | 17 | 18 | func _execute(_event_node=null) -> void: 19 | finish() 20 | 21 | 22 | func set_text(value:String) -> void: 23 | text = value 24 | property_list_changed_notify() 25 | emit_changed() 26 | 27 | func _get(property: String): 28 | if property == "continue_at_end_ignore": 29 | return true 30 | -------------------------------------------------------------------------------- /addons/event_system_plugin/events/condition.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Event 3 | class_name EventCondition 4 | 5 | ## Conditional event that executes true events if the evaluated [code]condition[/code] 6 | ## 7 | ## Works like if-statements. The [code]condition[/code] is evaluated according the 8 | ## assigned [code]event_node[/code] 9 | 10 | const _Utils = preload("res://addons/event_system_plugin/core/utils.gd") 11 | 12 | export(String) var condition:String = "" 13 | 14 | var next_event 15 | 16 | func _execute() -> void: 17 | var variables:Dictionary = _Utils.get_property_values_from(get_event_node()) 18 | 19 | var evaluated_condition = _Utils.evaluate(condition, get_event_node(), variables) 20 | 21 | if evaluated_condition and (str(evaluated_condition) != condition): 22 | next_event 23 | else: 24 | next_event 25 | 26 | next_event = "0" 27 | 28 | finish() 29 | 30 | 31 | func _get(property: String): 32 | if property == "custom_event_node": 33 | return load("res://addons/event_system_plugin/nodes/editor/event_node/event_condition_node.gd").new() 34 | 35 | 36 | func _init() -> void: 37 | event_name = "Condition" 38 | event_color = Color("#FBB13C") 39 | event_preview_string = "[ {condition} ]:" 40 | event_hint = "Similar to if-else statement.\nEvaluates a condition and execute events accordingly." 41 | event_category = "Logic" 42 | continue_at_end = true 43 | event_uses_subevents = true 44 | 45 | 46 | func _get_property_list() -> Array: 47 | var p := [] 48 | 49 | var usage:int = PROPERTY_USAGE_EDITOR 50 | usage |= PROPERTY_USAGE_STORAGE 51 | p.append({"name":"_events_if", "type":TYPE_OBJECT, "usage":usage}) 52 | 53 | p.append({"name":"_events_else","type":TYPE_OBJECT, "usage":usage}) 54 | return p 55 | -------------------------------------------------------------------------------- /addons/event_system_plugin/events/emit_signal.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Event 3 | class_name EventEmitSignal 4 | 5 | ## Makes EventManager emits [signal EventManager.custom_signal] with string value [code]data[/code]. 6 | 7 | export(String) var data:String = "" setget _set_data 8 | 9 | func _init() -> void: 10 | event_name = "Emit Signal" 11 | event_color = Color("EB5E55") 12 | event_preview_string = "with [ '{data}' ] value" 13 | event_hint = "Emits EventManager 'custom_signal' with passed value as string" 14 | event_category = "Node" 15 | 16 | func _execute() -> void: 17 | get_event_manager_node().emit_signal("custom_signal", data) 18 | finish() 19 | 20 | 21 | func _set_data(value:String) -> void: 22 | data = value 23 | emit_changed() 24 | property_list_changed_notify() 25 | -------------------------------------------------------------------------------- /addons/event_system_plugin/events/end_timeline.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Event 3 | 4 | ## Ends the timeline execution. 5 | 6 | func _init() -> void: 7 | event_color = Color("EB5E55") 8 | event_name = "End Timeline" 9 | event_hint = "Terminates the execution of the timeline at this point" 10 | 11 | 12 | func _execute() -> void: 13 | get_event_manager_node().call("_notify_timeline_end") 14 | get_event_manager_node().set("current_timeline", "") 15 | finish() 16 | -------------------------------------------------------------------------------- /addons/event_system_plugin/events/goto.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Event 3 | class_name EventGoTo 4 | 5 | ## Makes EventManager execute the defined event in [code]next_event[/code] instead 6 | ## of the directly next one. 7 | 8 | # The next event hint of this event. ";" 9 | var next_event:String = "" setget set_next_event 10 | 11 | func _init() -> void: 12 | event_name = "Go to" 13 | event_color = Color("#FBB13C") 14 | event_preview_string = "event [{next_event}]" 15 | continue_at_end = true 16 | event_category = "Logic" 17 | event_hint = "Helper event to define the next event after this event" 18 | 19 | func set_next_event(value:String) -> void: 20 | next_event = value 21 | emit_changed() 22 | property_list_changed_notify() 23 | 24 | 25 | func _get(property): 26 | if property == "event_node_path_ignore": 27 | return true 28 | if property == "continue_at_end_ignore": 29 | return true 30 | 31 | 32 | func _get_property_list(): 33 | var p := [] 34 | p.append({"name":"next_event", "type":TYPE_STRING}) 35 | return p 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/events/hide.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends "res://addons/event_system_plugin/events/call_from.gd" 3 | class_name EventHide 4 | 5 | ## Makes the [code]event_node[/code] be hidden if possible. 6 | 7 | func _init() -> void: 8 | event_color = Color("EB5E55") 9 | event_name = "Hide" 10 | event_category = "Node" 11 | method = "set" 12 | args = ["visible", false] 13 | event_preview_string = "{event_node_path}" 14 | 15 | 16 | func _get(property: String): 17 | if property == "method_ignore": 18 | return true 19 | if property == "args_ignore": 20 | return true 21 | -------------------------------------------------------------------------------- /addons/event_system_plugin/events/set.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends "res://addons/event_system_plugin/events/call_from.gd" 3 | class_name EventSet 4 | 5 | ## Sets [code]variable_name[/code] be [code]variable_value[/code] in [code]event_node[/code]. 6 | 7 | export(String) var variable_name:String = "" setget set_var_name 8 | export(String) var variable_value:String = "" setget set_var_value 9 | 10 | func _init() -> void: 11 | event_name = "Set" 12 | event_category = "Node" 13 | event_color = Color("EB5E55") 14 | event_preview_string = "[ {variable_name} ] to be [ {variable_value} ]" 15 | continue_at_end = true 16 | method = "set" 17 | args = ["",""] 18 | 19 | 20 | func set_var_name(value:String) -> void: 21 | variable_name = value 22 | args[0] = variable_name 23 | emit_changed() 24 | property_list_changed_notify() 25 | 26 | 27 | func set_var_value(value:String) -> void: 28 | variable_value = value 29 | args[1] = variable_value 30 | emit_changed() 31 | property_list_changed_notify() 32 | 33 | 34 | func _get(property: String): 35 | if property == "continue_at_end_ignore": 36 | return true 37 | if property == "method_ignore": 38 | return true 39 | if property == "args_ignore": 40 | return true 41 | -------------------------------------------------------------------------------- /addons/event_system_plugin/events/show.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends "res://addons/event_system_plugin/events/call_from.gd" 3 | class_name EventShow 4 | 5 | ## Makes the [code]event_node[/code] be shown if possible. 6 | 7 | func _init() -> void: 8 | event_color = Color("EB5E55") 9 | event_name = "Show" 10 | event_category = "Node" 11 | method = "set" 12 | args = ["visible", true] 13 | event_preview_string = "{event_node_path}" 14 | 15 | 16 | func _get(property: String): 17 | if property == "method_ignore": 18 | return true 19 | if property == "args_ignore": 20 | return true 21 | -------------------------------------------------------------------------------- /addons/event_system_plugin/events/wait.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Event 3 | class_name EventWait 4 | 5 | ## Pauses the timeline execution by [code]wait_time[/code] seconds. 6 | 7 | export(float) var wait_time = 0.0 setget set_wait_time 8 | 9 | func _init(): 10 | event_name = "Wait" 11 | event_color = Color("#FBB13C") 12 | event_category = "Logic" 13 | event_preview_string = "[{wait_time}] seconds before the next event." 14 | 15 | 16 | func _execute() -> void: 17 | var _timer = get_event_node().get_tree().create_timer(wait_time) 18 | _timer.connect("timeout", self, "finish") 19 | 20 | 21 | func set_wait_time(value:float) -> void: 22 | wait_time = value 23 | emit_changed() 24 | property_list_changed_notify() 25 | -------------------------------------------------------------------------------- /addons/event_system_plugin/godot_plugin.gd: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | # Copyright (c) 2022 AnidemDex 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | # Take a look at the original repo to report issues or update script 24 | # https://github.com/AnidemDex/Godot-PluginTemplate 25 | 26 | tool 27 | extends EditorPlugin 28 | 29 | ##### 30 | # Plugin classes 31 | ##### 32 | 33 | class WelcomeNode extends WindowDialog: 34 | 35 | ## 36 | ## The node popup that appears when you call show_welcome_node() 37 | ## 38 | 39 | var _main_panel:TabContainer 40 | var _margin:MarginContainer 41 | var _menu:PopupMenu 42 | 43 | var _plugin_data:ConfigFile 44 | 45 | func _ready() -> void: 46 | add_stylebox_override("panel", get_stylebox("panel", "ProjectSettingsEditor")) 47 | 48 | _margin = MarginContainer.new() 49 | _margin.set_anchors_and_margins_preset(Control.PRESET_WIDE, Control.PRESET_MODE_KEEP_SIZE) 50 | _margin.add_constant_override("margin_top", 8) 51 | _margin.add_constant_override("margin_left", 2) 52 | _margin.add_constant_override("margin_right", 2) 53 | _margin.add_constant_override("margin_bottom", 16) 54 | add_child(_margin) 55 | 56 | _main_panel = TabContainer.new() 57 | _margin.add_child(_main_panel) 58 | 59 | _menu = PopupMenu.new() 60 | add_child(_menu) 61 | _main_panel.set_popup(_menu) 62 | 63 | add_tab("Information") 64 | add_tab("Plugin Info") 65 | 66 | var label = Label.new() 67 | label.text = "This plugin uses Plugin Template v%s"%__PLUGIN_VERSION 68 | add_child(label) 69 | label.set_anchors_and_margins_preset(Control.PRESET_BOTTOM_RIGHT) 70 | label.add_color_override("font_color", get_color("disabled_font_color", "Editor")) 71 | 72 | var plugin_information:VBoxContainer = get_tab_by_name("Plugin Info") 73 | 74 | if _plugin_data: 75 | var keys = _plugin_data.get_section_keys(__Constants.PLUGIN) 76 | for key in keys: 77 | var value = _plugin_data.get_value(__Constants.PLUGIN, key, "") 78 | var info_label := Label.new() 79 | info_label.text = "{key}: {value}".format({"key":key.capitalize(), "value":value}) 80 | plugin_information.add_child(info_label) 81 | 82 | 83 | ## Adds a tab to welcome popup 84 | func add_tab(tab_name:String) -> void: 85 | var tab = VBoxContainer.new() 86 | tab.name = tab_name 87 | _main_panel.add_child(tab) 88 | 89 | 90 | ## Returns a Control node if find the node by its name 91 | func get_tab_by_name(tab_name) -> Control: 92 | var tab:Control = null 93 | for tab_idx in _main_panel.get_tab_count(): 94 | var title = _main_panel.get_tab_title(tab_idx) 95 | if title == tab_name: 96 | tab = get_tab_by_idx(tab_idx) 97 | break 98 | return tab 99 | 100 | 101 | ## Returns a Control node if find the node by its index 102 | func get_tab_by_idx(tab_idx:int) -> Control: 103 | var tab:Control = _main_panel.get_tab_control(tab_idx) 104 | return tab 105 | 106 | ## Returns the TabContainer used by the node. DO NOT free it or you may cause 107 | ## issues with nodes that deppends on this node. 108 | func get_tab_container() -> TabContainer: 109 | return _main_panel 110 | 111 | 112 | ## Sets the data of the plugin using this node. Used internally 113 | func set_plugin_data(plugin_data:ConfigFile) -> void: 114 | _plugin_data = plugin_data 115 | 116 | 117 | ##### 118 | # Plugin methods 119 | ##### 120 | 121 | ## Returns true if the plugin is editable. Useful for debug. 122 | ## To enable it, add "editable=true" in plugin.cfg file under "plugin" section. 123 | func is_plugin_editable() -> bool: 124 | return __plugin_data.get_value(__Constants.PLUGIN, "editable", false) 125 | 126 | 127 | ## Returns the path of the script file 128 | func get_plugin_path() -> String: 129 | var script:Script = get_script() as Script 130 | var path:String = "" 131 | # No idea why this should return null but anyway... 132 | if script: 133 | path = script.resource_path 134 | return path 135 | 136 | 137 | ## Returns the path of the folder that contains the plugin script. 138 | func get_plugin_folder_path() -> String: 139 | var path:String = get_plugin_path() 140 | return path.get_base_dir() 141 | 142 | 143 | ## Returns the plugin's author. 144 | func get_plugin_author() -> String: 145 | return __plugin_data.get_value(__Constants.PLUGIN, __Constants.AUTHOR, "") 146 | 147 | 148 | ## Returns the plugin's version 149 | func get_plugin_version() -> String: 150 | return str(__plugin_data.get_value(__Constants.PLUGIN, __Constants.VERSION, "")) 151 | 152 | 153 | ## Returns the name of the plugin defined in plugin.cfg. 154 | func get_plugin_real_name() -> String: 155 | return __plugin_data.get_value(__Constants.PLUGIN, __Constants.NAME, "") 156 | 157 | 158 | ## Returns the plugin's description. 159 | func get_plugin_description() -> String: 160 | return __plugin_data.get_value(__Constants.PLUGIN, __Constants.DESCRIPTION, "") 161 | 162 | 163 | ## Returns the plugin's docs url. Defined in plugin.cfg as "docs" under plugin section. 164 | func get_plugin_docs_url() -> String: 165 | return __plugin_data.get_value(__Constants.PLUGIN, __Constants.DOCS, "") 166 | 167 | 168 | ## Returns the plugin's repository url. Defined in plugin.cfg as "repository" under plugin section. 169 | func get_plugin_repository() -> String: 170 | return __plugin_data.get_value(__Constants.PLUGIN, __Constants.REPOSITORY, "") 171 | 172 | 173 | ## Returns the plugin's license. This can be whatever the dev needs, from a URL to a simple string. 174 | ## Defined in plugin.cfg as "license" under plugin section. 175 | func get_plugin_license() -> String: 176 | return __plugin_data.get_value(__Constants.PLUGIN, __Constants.LICENSE, "") 177 | 178 | 179 | ## Returns the plugin configuration file. This is the equivalent data file readed from plugin.cfg. 180 | ## All the plugin data will be saved to plugin.cfg. 181 | func get_plugin_data() -> ConfigFile: 182 | return __plugin_data 183 | 184 | 185 | ## Returns the WelcomeNode popup used by the plugin. 186 | ## See WelcomeNode. 187 | func get_plugin_welcome_node() -> WelcomeNode: 188 | return __welcome_node 189 | 190 | 191 | ## Registers a node as a node that belongs to this plugin. 192 | ## The node will be automatically freed when the plugin gets removed. 193 | func register_plugin_node(node:Node) -> void: 194 | assert(node != null) 195 | 196 | assert(not node in __registered_nodes, "The node %s is already registered"%node) 197 | __registered_nodes.append(node) 198 | 199 | 200 | ## Alternative to add_control_to_dock(). 201 | ## It registers a node as a node that belongs to this plugin and save its dock position 202 | ## even if the plugin is disabled. 203 | ## In order to save the node position in docks, you need to give it a name before register the node. 204 | func register_control_to_dock(control:Control, dock_slot:int = -1) -> void: 205 | assert(control != null) 206 | 207 | # Restore previously saved slot if exists 208 | var plugin_data:ConfigFile = get_plugin_data() 209 | if control.name != "": 210 | control.name = control.name.capitalize().replace(" ", "") 211 | if dock_slot < 0: 212 | var dock_slot_name:String = plugin_data.get_value(__Constants.DOCK, control.name, "DOCK_SLOT_LEFT_UL") 213 | dock_slot = ClassDB.class_get_integer_constant("EditorPlugin", dock_slot_name) 214 | 215 | register_plugin_node(control) 216 | add_control_to_dock(dock_slot, control) 217 | 218 | assert(not control in __nodes_in_dock, "The node %s is already in dock"%control) 219 | __nodes_in_dock.append(control) 220 | 221 | 222 | func register_editor_plugin(plugin:EditorInspectorPlugin) -> void: 223 | assert(not plugin in __registered_editor_plugins, "The plugin %s is already registered"%plugin) 224 | __registered_editor_plugins.append(plugin) 225 | add_inspector_plugin(plugin) 226 | 227 | 228 | ## Adds a node to the editor base control node. 229 | ## This is similar to do get_editor_interface().get_base_control().add_child() 230 | ## but it registers the node as a node that belongs to this plugin. 231 | func add_editor_node(node:Node) -> void: 232 | if not node in __registered_nodes: 233 | register_plugin_node(node) 234 | 235 | if not node.is_inside_tree(): 236 | get_editor_interface().get_base_control().add_child(node) 237 | 238 | 239 | ## Shows the welcome node. 240 | func show_welcome_node() -> void: 241 | var welcome_node:Control = get_plugin_welcome_node() 242 | # For some reason, hot reload makes all childs be out of the tree 243 | if not welcome_node.is_inside_tree(): 244 | add_editor_node(welcome_node) 245 | get_plugin_welcome_node().popup_centered_ratio(0.45) 246 | 247 | 248 | ## Shows the plugin version button. 249 | ## VersionButton will appear next to Editor's version button. 250 | func show_plugin_version_button() -> void: 251 | __version_button.show() 252 | 253 | 254 | ## Request, from another plugin, any method with variable number of arguments. 255 | ## `from_plugin` is plugin's name (defined with [get_plugin_name()] wich is the plugin real name 256 | ## by default. 257 | ## `method` is the method to call in the other plugin. 258 | ## `args` is an array that contains the arguments of the method call. 259 | ## This function only works with other plugins that uses PluginTemplate 260 | func request(from_plugin:String, method:String, args:=[]): 261 | var plugin:EditorPlugin = get_plugin_or_null(from_plugin) 262 | if plugin == null: 263 | return 264 | 265 | assert(plugin.has_method(method)) 266 | if plugin.has_method(method): 267 | return plugin.callv(method, args) 268 | 269 | 270 | ## Gets another plugin with `plugin_name`. 271 | ## `plugin_name` is plugin's name (defined with [get_plugin_name()] wich is the plugin real name 272 | ## by default. 273 | ## This function only works with other plugins that uses PluginTemplate. Returns null if was unable 274 | ## to find the plugin. 275 | func get_plugin_or_null(plugin_name:String) -> EditorPlugin: 276 | if Engine.has_meta(plugin_name): 277 | return Engine.get_meta(plugin_name) as EditorPlugin 278 | return null 279 | 280 | ## Reloads plugin data from plugin.cfg 281 | func reload_plugin_data() -> void: 282 | var _err = __plugin_data.load(get_plugin_folder_path()+"/plugin.cfg") 283 | assert(_err == OK, "There was an error while loading plugin data: %s"%_err) 284 | 285 | #### 286 | # "Virtual" methods 287 | #### 288 | 289 | func _get_plugin_name() -> String: 290 | return get_plugin_real_name() 291 | 292 | func _get_state() -> Dictionary: 293 | var plugin_data:ConfigFile = get_plugin_data() 294 | var state = plugin_data.get_value("state", "plugin_state", {}) 295 | return state 296 | 297 | ##### 298 | # Virtual functions replaced with custom ones 299 | # Why? Because the template needs those **and** virtual methods 300 | # are usually marked with a _ prefix in Godot. 301 | # Ok but why all? Just in case I need to add different behaviours to those. 302 | ##### 303 | 304 | func apply_changes() -> void: 305 | if has_method("_apply_changes"): 306 | call("_apply_changes") 307 | 308 | 309 | func build() -> bool: 310 | if has_method("_build"): 311 | return call("_build") 312 | return true 313 | 314 | 315 | func clear() -> void: 316 | if has_method("_clear"): 317 | call("_clear") 318 | 319 | 320 | func disable_plugin() -> void: 321 | if has_method("_disable_plugin"): 322 | call("_disable_plugin") 323 | 324 | 325 | func edit(object:Object) -> void: 326 | if has_method("_edit"): 327 | call("_edit", object) 328 | 329 | 330 | func enable_plugin() -> void: 331 | if has_method("_enable_plugin"): 332 | call("_enable_plugin") 333 | 334 | 335 | func forward_canvas_draw_over_viewport(overlay: Control) -> void: 336 | if has_method("_forward_canvas_draw_over_viewport"): 337 | call("_forward_canvas_draw_over_viewport", overlay) 338 | 339 | 340 | func forward_canvas_force_draw_over_viewport(overlay: Control) -> void: 341 | if has_method("_forward_canvas_force_draw_over_viewport"): 342 | call("_forward_canvas_force_draw_over_viewport", overlay) 343 | 344 | 345 | func forward_canvas_gui_input(event: InputEvent) -> bool: 346 | if has_method("_forward_canvas_gui_input"): 347 | return call("_forward_canvas_gui_input", event) 348 | return false 349 | 350 | 351 | func forward_spatial_draw_over_viewport(overlay: Control) -> void: 352 | if has_method("_forward_spatial_draw_over_viewport"): 353 | call("_forward_spatial_draw_over_viewport", overlay) 354 | 355 | 356 | func forward_spatial_force_draw_over_viewport(overlay: Control) -> void: 357 | if has_method("_forward_spatial_force_draw_over_viewport"): 358 | call("_forward_spatial_force_draw_over_viewport", overlay) 359 | 360 | 361 | func forward_spatial_gui_input(camera: Camera, event: InputEvent) -> bool: 362 | if has_method("_forward_spatial_gui_input"): 363 | return call("_forward_spatial_gui_input", camera, event) 364 | return false 365 | 366 | 367 | func get_breakpoints() -> PoolStringArray: 368 | if has_method("_get_breakpoints"): 369 | return call("_get_breakpoints") 370 | return PoolStringArray() 371 | 372 | 373 | func get_plugin_icon() -> Texture: 374 | if has_method("_get_plugin_icon"): 375 | return call("_get_plugin_icon") 376 | return get_editor_interface().get_base_control().get_icon("Node","EditorIcons") 377 | 378 | 379 | func get_plugin_name() -> String: 380 | return _get_plugin_name() 381 | 382 | 383 | func get_state() -> Dictionary: 384 | return _get_state() 385 | 386 | 387 | func get_window_layout(layout: ConfigFile) -> void: 388 | # This is called when you call queue_save_layout() 389 | # [docks] 390 | # dock_?_x where ? can be filesystem_* split or hsplit and x is an integer 391 | # [EditorNode] 392 | # open_scenes [] 393 | # [ScriptEditor] 394 | # open_scripts [] Array of dicts 395 | # open_help [] PoolStringArray 396 | # split_offset 397 | var plugin_data:ConfigFile = get_plugin_data() 398 | 399 | if plugin_data.has_section(__Constants.DOCK): 400 | plugin_data.erase_section(__Constants.DOCK) 401 | 402 | var dock_nodes_names = [] 403 | for node in __nodes_in_dock: 404 | dock_nodes_names.append(node.name) 405 | 406 | for key in layout.get_section_keys(__Constants.DOCK): 407 | key = str(key) 408 | 409 | # Avoid other docks properties 410 | if key.length()>6: 411 | continue 412 | 413 | var dock_slot:int = int(key[5])-1 414 | var c_enum = ClassDB.class_get_enum_constants("EditorPlugin", "DockSlot") 415 | var names:String = layout.get_value(__Constants.DOCK, key, "") 416 | var node_names := names.split(",") 417 | for node_name in node_names: 418 | if node_name in dock_nodes_names: 419 | plugin_data.set_value(__Constants.DOCK, node_name, c_enum[dock_slot]) 420 | 421 | if has_method("_get_window_layout"): 422 | call("_get_window_layout", layout) 423 | 424 | 425 | func handles(object: Object) -> bool: 426 | if has_method("_handles"): 427 | return call("_handles", object) 428 | return false 429 | 430 | 431 | func has_main_screen() -> bool: 432 | if has_method("_has_main_screen"): 433 | return call("_has_main_screen") 434 | return false 435 | 436 | 437 | func make_visible(visible: bool) -> void: 438 | if has_method("_make_visible"): 439 | call("_make_visible", visible) 440 | 441 | 442 | func save_external_data() -> void: 443 | var plugin_data:ConfigFile = get_plugin_data() 444 | 445 | if __plugin_sensible_data_modified: 446 | var message = "'{plugin}' sensible data was modified. The plugin will be reloaded." 447 | var plugin_good_name = get_plugin_folder_path().split("/")[-1] 448 | message = message.format({"plugin":get_plugin_name()}) 449 | OS.call_deferred("alert", message) 450 | get_editor_interface().call_deferred("set_plugin_enabled", plugin_good_name, false) 451 | get_editor_interface().call_deferred("set_plugin_enabled", plugin_good_name, true) 452 | var _err = plugin_data.save(get_plugin_folder_path()+"/plugin.cfg") 453 | 454 | if has_method("_save_external_data"): 455 | call("_save_external_data") 456 | 457 | assert(_err == OK, "There was a problem while saving plugin data: %s"%_err) 458 | 459 | 460 | func set_state(state: Dictionary) -> void: 461 | var plugin_data:ConfigFile = get_plugin_data() 462 | var key := __Constants.PLUGIN+"_"+__Constants.STATE 463 | plugin_data.set_value(__Constants.STATE, key, state) 464 | if has_method("_set_state"): 465 | call("_set_state", state) 466 | 467 | 468 | func set_window_layout(layout: ConfigFile) -> void: 469 | # This is called when the plugin was enabled while the editor is restoring its layout 470 | # see get_window_layout 471 | if has_method("_set_window_layout"): 472 | call("_set_window_layout", layout) 473 | 474 | ##### 475 | # Godot methods 476 | ##### 477 | 478 | func _enter_tree() -> void: 479 | add_editor_node(__welcome_node) 480 | __add_plugin_version_button() 481 | 482 | 483 | func _ready() -> void: 484 | __register_itself_on_editor() 485 | __register_plugin_template() 486 | 487 | 488 | func _exit_tree() -> void: 489 | __cleanup() 490 | 491 | 492 | func _set(property: String, value) -> bool: 493 | var plugin_data := get_plugin_data() 494 | var has_property := false 495 | 496 | for section in plugin_data.get_sections(): 497 | if property.begins_with("plugin_"): 498 | property = property.replace("plugin_", "") 499 | __plugin_sensible_data_modified = true 500 | has_property = plugin_data.has_section_key(section, property) 501 | if has_property: 502 | plugin_data.set_value(section, property, value) 503 | if __plugin_sensible_data_modified: 504 | property_list_changed_notify() 505 | has_property = false # let default values go up 506 | 507 | return has_property 508 | 509 | 510 | func _get(property: String): 511 | var plugin_data := get_plugin_data() 512 | for section in plugin_data.get_sections(): 513 | if property.begins_with("plugin_"): 514 | property = property.replace("plugin_", "") 515 | if plugin_data.has_section_key(section, property): 516 | return plugin_data.get_value(section, property, null) 517 | 518 | 519 | func _get_property_list() -> Array: 520 | var p := [] 521 | 522 | for section in __plugin_data.get_sections(): 523 | var pre := "" 524 | var _section:String = str(section) 525 | 526 | if _section == __Constants.PLUGIN: 527 | pre = _section+"_" 528 | 529 | p.append({"name":_section.capitalize(), "type":TYPE_NIL, "usage":PROPERTY_USAGE_CATEGORY}) 530 | 531 | for key in __plugin_data.get_section_keys(section): 532 | var _key:String = str(key) 533 | var _value = __plugin_data.get_value(_section, _key) 534 | var _type:int = typeof(_value) 535 | var usage_hint := PROPERTY_USAGE_EDITOR 536 | 537 | if _section == __Constants.PLUGIN: 538 | usage_hint |= PROPERTY_USAGE_RESTART_IF_CHANGED 539 | if not is_plugin_editable(): 540 | usage_hint = 0 541 | 542 | p.append({"name":pre+key, "type":_type, "usage":usage_hint}) 543 | return p 544 | 545 | 546 | func _init() -> void: 547 | __registered_nodes = [] 548 | __nodes_in_dock = [] 549 | 550 | __plugin_data = ConfigFile.new() 551 | reload_plugin_data() 552 | 553 | name = get_plugin_name() 554 | 555 | __welcome_node = WelcomeNode.new() 556 | __welcome_node.set_plugin_data(__plugin_data) 557 | __welcome_node.window_title = get_plugin_name().capitalize() 558 | register_plugin_node(__welcome_node) 559 | 560 | __version_button = ToolButton.new() 561 | register_plugin_node(__version_button) 562 | 563 | 564 | ##### 565 | # Private 566 | ##### 567 | 568 | # what is an struct? 569 | class __Constants: 570 | const PLUGIN = "plugin" 571 | const VERSION = "version" 572 | const NAME = "name" 573 | const AUTHOR = "author" 574 | const SCRIPT = "script" 575 | const DESCRIPTION = "description" 576 | const DOCS = "docs" 577 | const REPOSITORY = "repository" 578 | const LICENSE = "license" 579 | const PLUGIN_TEMPLATE = "PluginTemplateHandler" 580 | const STATE = "state" 581 | const DOCK = "docks" 582 | 583 | 584 | class __Logger: 585 | # Future idea: make a logger using CassianoBelniak/katuiche-colorful-console 586 | # it has to be an static class available in the whole editor 587 | enum LogType {DEBUG, INFO, WARNING, ERROR} 588 | 589 | 590 | class __PluginTemplate extends EditorPlugin: 591 | class __NodeHandler extends EditorInspectorPlugin: 592 | 593 | var ignore_category = false 594 | 595 | func can_handle(object: Object) -> bool: 596 | return object is EditorPlugin 597 | 598 | 599 | func parse_begin(_object: Object) -> void: 600 | pass 601 | 602 | 603 | func parse_category(_object: Object, category: String) -> void: 604 | ignore_category = "Node" == category 605 | 606 | 607 | func parse_property(_object: Object, _type: int, _path: String, _hint: int, _hint_text: String, _usage: int) -> bool: 608 | if ignore_category: 609 | return true 610 | return false 611 | 612 | 613 | var node_handler := __NodeHandler.new() 614 | 615 | func _enter_tree() -> void: 616 | add_inspector_plugin(node_handler) 617 | 618 | 619 | func _ready() -> void: 620 | __register_itself_on_editor() 621 | 622 | 623 | func _exit_tree() -> void: 624 | remove_inspector_plugin(node_handler) 625 | 626 | # Copied from godot_plugin since we can't extend itself 627 | func __register_itself_on_editor() -> void: 628 | Engine.set_meta(__Constants.PLUGIN_TEMPLATE, self) 629 | 630 | 631 | const __PLUGIN_VERSION = 0.1 632 | 633 | var __plugin_data:ConfigFile 634 | var __welcome_node:WelcomeNode 635 | var __version_button:BaseButton 636 | 637 | var __registered_nodes:Array = [] 638 | var __registered_editor_plugins:Array = [] 639 | var __nodes_in_dock:Array = [] 640 | 641 | var __plugin_sensible_data_modified:bool = false 642 | 643 | func __add_plugin_version_button() -> void: 644 | if __version_button.is_inside_tree(): 645 | return 646 | 647 | var _v = {"version":get_plugin_version(), "plugin_name":get_plugin_name()} 648 | 649 | __version_button.set("text", "[{version}]".format(_v)) 650 | __version_button.hint_tooltip = "{plugin_name} version {version}".format(_v) 651 | var _e = __version_button.connect("pressed", self, "__WelcomeButton_pressed") 652 | 653 | var _new_color = __version_button.get_color("font_color") 654 | _new_color.a = 0.6 655 | __version_button.add_color_override("font_color", _new_color) 656 | __version_button.size_flags_vertical = Control.SIZE_EXPAND_FILL 657 | 658 | var _dummy := Control.new() 659 | var _dock_button := add_control_to_bottom_panel(_dummy, "dummy") 660 | _dock_button.get_parent().get_parent().add_child(__version_button) 661 | _dock_button.get_parent().get_parent().move_child(__version_button, 1) 662 | remove_control_from_bottom_panel(_dummy) 663 | _dummy.free() 664 | 665 | __version_button.hide() 666 | 667 | 668 | func __request_configuration() -> void: 669 | if not is_instance_valid(get_editor_interface().get_edited_scene_root()): 670 | return 671 | get_editor_interface().inspect_object(self) 672 | 673 | 674 | func __register_itself_on_editor() -> void: 675 | # Technically we can use get_tree(), but I don't rely on tree order 676 | Engine.set_meta(get_plugin_name(), self) 677 | add_tool_menu_item(get_plugin_name(), self, "__ToolMenu_item_pressed") 678 | var _e = connect("tree_exiting", self, "remove_tool_menu_item", [get_plugin_name()]) 679 | 680 | 681 | func __register_plugin_template() -> void: 682 | var plugin:EditorPlugin = get_plugin_or_null(__Constants.PLUGIN_TEMPLATE) as EditorPlugin 683 | if plugin != null: 684 | return 685 | plugin = __PluginTemplate.new() 686 | plugin.name = __Constants.PLUGIN_TEMPLATE 687 | get_parent().add_child(plugin) 688 | 689 | 690 | func __WelcomeButton_pressed() -> void: 691 | __request_configuration() 692 | show_welcome_node() 693 | 694 | 695 | func __ToolMenu_item_pressed(_d): 696 | __request_configuration() 697 | show_welcome_node() 698 | 699 | 700 | func __cleanup() -> void: 701 | queue_save_layout() 702 | for node in __registered_nodes: 703 | if not is_instance_valid(node): 704 | # For some reason is null??? 705 | continue 706 | 707 | if node in __nodes_in_dock: 708 | remove_control_from_docks(node) 709 | 710 | node.free() 711 | 712 | for plugin in __registered_editor_plugins: 713 | plugin = plugin as EditorPlugin 714 | if not plugin: 715 | # why is this not a valid plugin??? 716 | continue 717 | remove_inspector_plugin(plugin) 718 | 719 | __registered_nodes.clear() 720 | __nodes_in_dock.clear() 721 | 722 | save_external_data() 723 | -------------------------------------------------------------------------------- /addons/event_system_plugin/icon.png: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:1a444322a7d5f8a4e7e2e109299e3f2d68ab225030bfeeaa407d9f439993dff9 3 | size 5329 4 | -------------------------------------------------------------------------------- /addons/event_system_plugin/icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/icon.png-2cbbc86fe8426a381ba771f472ef31e5.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://addons/event_system_plugin/icon.png" 13 | dest_files=[ "res://.import/icon.png-2cbbc86fe8426a381ba771f472ef31e5.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/category_manager.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends PanelContainer 3 | 4 | const EventButtonNode = preload("res://addons/event_system_plugin/nodes/editor/event_node/event_node.gd") 5 | const EventClass = preload("res://addons/event_system_plugin/resources/event_class/event_class.gd") 6 | const TimelineClass = preload("res://addons/event_system_plugin/resources/timeline_class/timeline_class.gd") 7 | 8 | class EventButton extends PanelContainer: 9 | var event_script:Script 10 | var icon 11 | var text 12 | 13 | var button:ToolButton 14 | var border:PanelContainer 15 | var icon_node:TextureRect 16 | var spacer:Control 17 | var text_node:Label 18 | 19 | func get_drag_data(position): 20 | var node = EventButtonNode.new() 21 | node.event = event_script.new() 22 | node.call_deferred("update_values") 23 | set_drag_preview(node) 24 | return {"event":event_script.new()} 25 | 26 | func _ready(): 27 | var dummy = event_script.new() 28 | 29 | if not text: 30 | text = dummy.get("event_name") 31 | 32 | if not icon: 33 | icon = dummy.get("event_icon") 34 | 35 | text_node.text = text 36 | icon_node.texture = icon 37 | hint_tooltip = "%s" % dummy.get("event_hint") 38 | 39 | var style := get_stylebox("border", "EventButton").duplicate() 40 | style.set("bg_color", dummy.get("event_color")) 41 | 42 | border.add_stylebox_override("panel", style) 43 | add_stylebox_override("panel", get_stylebox("normal", "EventButton")) 44 | 45 | 46 | func _init(): 47 | rect_clip_content = true 48 | size_flags_vertical = SIZE_EXPAND_FILL 49 | 50 | button = ToolButton.new() 51 | button.show_behind_parent = true 52 | button.mouse_filter = Control.MOUSE_FILTER_PASS 53 | add_child(button) 54 | 55 | icon_node = TextureRect.new() 56 | icon_node.expand = true 57 | icon_node.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED 58 | icon_node.focus_mode = Control.FOCUS_NONE 59 | icon_node.mouse_filter = Control.MOUSE_FILTER_IGNORE 60 | var scale:float = 1 61 | if Engine.editor_hint: 62 | var plugin:EditorPlugin = EditorPlugin.new() 63 | scale = plugin.get_editor_interface().get_editor_scale() 64 | plugin.free() 65 | icon_node.rect_min_size = Vector2(24,24) * scale 66 | 67 | text_node = Label.new() 68 | text_node.focus_mode = Control.FOCUS_NONE 69 | text_node.mouse_filter = Control.MOUSE_FILTER_IGNORE 70 | 71 | border = PanelContainer.new() 72 | border.focus_mode = Control.FOCUS_NONE 73 | border.mouse_filter = Control.MOUSE_FILTER_IGNORE 74 | border.rect_min_size.x = 4 75 | 76 | spacer = Control.new() 77 | spacer.focus_mode = Control.FOCUS_NONE 78 | spacer.mouse_filter = Control.MOUSE_FILTER_IGNORE 79 | spacer.rect_min_size = Vector2(2, 0) 80 | 81 | var hb := HBoxContainer.new() 82 | hb.size_flags_horizontal = SIZE_EXPAND_FILL 83 | hb.focus_mode = Control.FOCUS_NONE 84 | hb.mouse_filter = Control.MOUSE_FILTER_IGNORE 85 | hb.add_constant_override("separation", 0) 86 | hb.add_child(border) 87 | hb.add_child(icon_node) 88 | hb.add_child(spacer) 89 | hb.add_child(text_node) 90 | 91 | add_child(hb) 92 | 93 | 94 | class Category extends VBoxContainer: 95 | const FlowContainer = preload("res://addons/event_system_plugin/nodes/editor/flow_container.gd") 96 | 97 | signal event_button_added(button) 98 | 99 | var name_label:Label 100 | var event_scripts:Array = [] 101 | var button_container:FlowContainer 102 | 103 | func add_event(event) -> void: 104 | var event_script:Script = event.get_script() 105 | if event_script in event_scripts: 106 | return 107 | 108 | event_scripts.append(event_script) 109 | 110 | var btn := EventButton.new() 111 | btn.event_script = event_script 112 | # btn.icon_node.texture = event.event_icon 113 | # btn.text_node.text = event.get("event_name") 114 | # var event_hint := "{event_name}\n-----\n{event_hint}" 115 | # btn.hint_tooltip = event_hint.format({"event_name":event.get("event_name"), "event_hint":event.get("event_hint")}) 116 | button_container.add_child(btn) 117 | btn.add_color_override("font_color", get_color("font_color", "Editor")) 118 | btn.add_color_override("font_color_hover", get_color("accent_color", "Editor")) 119 | emit_signal("event_button_added", btn) 120 | 121 | 122 | func _set(property, value) -> bool: 123 | if property == "name": 124 | name = value 125 | name_label.text = value 126 | return true 127 | return false 128 | 129 | 130 | func _init(): 131 | event_scripts = [] 132 | name_label = Label.new() 133 | name_label.align = Label.ALIGN_CENTER 134 | var separator = HSeparator.new() 135 | separator.size_flags_horizontal = SIZE_EXPAND_FILL 136 | var hb = HBoxContainer.new() 137 | hb.size_flags_horizontal = SIZE_EXPAND_FILL 138 | hb.add_child(name_label) 139 | hb.add_child(separator) 140 | add_child(hb) 141 | 142 | button_container = FlowContainer.new() 143 | button_container.hseparation = 2 144 | button_container.vseparation = 1 145 | add_child(button_container) 146 | 147 | 148 | signal toolbar_button_pressed(button, event_script) 149 | 150 | var know_events:TimelineClass 151 | var categories:Dictionary = {} 152 | 153 | var _category_container:VBoxContainer 154 | 155 | func reload() -> void: 156 | categories.clear() 157 | 158 | for child in _category_container.get_children(): 159 | child.queue_free() 160 | 161 | create_categories() 162 | 163 | 164 | func create_categories() -> void: 165 | for event in know_events.get_events(): 166 | event = event as EventClass 167 | if not event: 168 | continue 169 | 170 | var category:String = event.event_category 171 | add_category(category) 172 | 173 | var category_node:Category = categories.get(category, null) 174 | category_node.add_event(event) 175 | 176 | 177 | func add_category(category_name:String) -> void: 178 | if category_name in categories: 179 | return 180 | 181 | var category:Category = Category.new() 182 | categories[category_name] = category 183 | 184 | category.connect("event_button_added", self, "_on_Category_event_button_added") 185 | category.name = category_name 186 | _category_container.add_child(category) 187 | 188 | 189 | func _enter_tree(): 190 | know_events = load("res://addons/event_system_plugin/resources/registered_events/registered_events.tres") 191 | 192 | if not know_events.is_connected("changed",self,"reload"): 193 | know_events.connect("changed",self,"reload") 194 | 195 | 196 | func _on_Category_event_button_added(event_button:EventButton) -> void: 197 | event_button.button.connect("pressed", self, "_on_Category_event_button_pressed", [event_button]) 198 | 199 | 200 | func _on_Category_event_button_pressed(event_button:EventButton) -> void: 201 | emit_signal("toolbar_button_pressed", event_button, event_button.event_script) 202 | 203 | 204 | func _notification(what: int) -> void: 205 | if what == NOTIFICATION_POST_ENTER_TREE: 206 | know_events.emit_changed() 207 | 208 | 209 | func _init(): 210 | categories = {} 211 | name = "CategoryManager" 212 | size_flags_vertical = SIZE_EXPAND_FILL 213 | rect_min_size = Vector2(128, 64) 214 | 215 | var _sc = ScrollContainer.new() 216 | _sc.size_flags_horizontal = SIZE_EXPAND_FILL 217 | _sc.size_flags_vertical = SIZE_EXPAND_FILL 218 | add_child(_sc) 219 | 220 | _category_container = VBoxContainer.new() 221 | _category_container.size_flags_horizontal = SIZE_EXPAND_FILL 222 | _category_container.size_flags_vertical = SIZE_EXPAND_FILL 223 | _sc.add_child(_category_container) 224 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/event_node/event_condition_node.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends "res://addons/event_system_plugin/nodes/editor/event_node/event_node.gd" 3 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/event_node/event_node.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends HBoxContainer 3 | 4 | const EventClass = preload("res://addons/event_system_plugin/resources/event_class/event_class.gd") 5 | const TimelineClass = preload("res://addons/event_system_plugin/resources/timeline_class/timeline_class.gd") 6 | const Utils = preload("res://addons/event_system_plugin/core/utils.gd") 7 | 8 | var event_button:Button 9 | 10 | ## Event related to this node 11 | var event:EventClass setget set_event 12 | 13 | ## Timeline that contains this event. Used as editor hint 14 | var timeline:TimelineClass 15 | var idx:int setget set_idx 16 | 17 | # Background 18 | var __bg:PanelContainer 19 | var __indent_node:Control 20 | var __header:HBoxContainer 21 | var __body:MarginContainer 22 | var __icon_container:PanelContainer 23 | var __icon_node:TextureRect 24 | var __event_label:Label 25 | var __event_preview_label:Label 26 | var __expand_button:CheckButton 27 | 28 | func update_values() -> void: 29 | __update_event_icon() 30 | __update_event_name() 31 | __update_preview_hint() 32 | __update_identation() 33 | 34 | if has_method("_update_values"): 35 | call("_update_values") 36 | 37 | 38 | func add_node_at_header(node:Control) -> void: 39 | __header.get_child(1).add_child(node) 40 | 41 | 42 | func add_node_at_body(node:Control) -> void: 43 | __expand_button.visible = true 44 | __body.get_child(0).add_child(node) 45 | 46 | 47 | func set_event(_event) -> void: 48 | if event and event.is_connected("changed",self,"update_values"): 49 | event.disconnect("changed",self,"update_values") 50 | 51 | event = _event 52 | 53 | if event != null: 54 | if not event.is_connected("changed",self,"update_values"): 55 | event.connect("changed",self,"update_values") 56 | name = event.event_name 57 | 58 | 59 | func set_idx(value:int) -> void: 60 | idx = value 61 | 62 | 63 | func set_indentation_level(level:int) -> void: 64 | if !is_instance_valid(__indent_node): 65 | return 66 | level = max(level, 0) 67 | __indent_node.rect_min_size.x = get_constant("indentation", "EventNode") * level 68 | 69 | 70 | func set_button_group(button_group:ButtonGroup) -> void: 71 | event_button.set_button_group(button_group) 72 | 73 | 74 | func _on_event_button_toggled(toggled:bool) -> void: 75 | var color:Color = Color.white 76 | var icon_color:Color = color 77 | if toggled: 78 | color = Color.cyan if not Engine.editor_hint else get_color("accent_color", "Editor") 79 | if event: 80 | icon_color = event.event_color 81 | 82 | event_button.self_modulate = color 83 | __icon_container.self_modulate = icon_color 84 | 85 | 86 | 87 | func _on_expand_toggled(toggled:bool) -> void: 88 | __body.visible = toggled 89 | 90 | 91 | func __update_event_name() -> void: 92 | var text := "{Event Name}" 93 | if event: 94 | text = event.event_name 95 | __event_label.text = text 96 | 97 | 98 | func __update_event_icon() -> void: 99 | var icon:Texture = get_icon("warning", "EditorIcons") 100 | var color:Color = get_color("") 101 | if event: 102 | icon = event.event_icon 103 | 104 | __icon_node.texture = icon 105 | 106 | 107 | func __update_preview_hint() -> void: 108 | var text:String = "" 109 | 110 | if event: 111 | text = event.event_preview_string 112 | 113 | if "next_event" in text: 114 | text = text.replace("next_event", "__next_event__") 115 | 116 | text = text.format(Utils.get_property_values_from(event)) 117 | if "next_event" in event: 118 | var data = str(event.get("next_event")).split(";", false, 1) 119 | var next_idx = -1 120 | var event_name = "???" 121 | var timeline_name = "" 122 | var hint_string = "{event_name}" 123 | var used_timeline = timeline 124 | 125 | if data.size() >= 1: 126 | next_idx = int(data[0]) 127 | if data.size() >= 2: 128 | timeline_name = str(data[1]) 129 | hint_string += " from {timeline_name}" 130 | if is_instance_valid(Engine.get_meta("EventSystem").timeline_editor._edited_node): 131 | used_timeline = Engine.get_meta("EventSystem").timeline_editor._edited_node.get_timeline(timeline_name) 132 | 133 | if used_timeline.get_event(next_idx): 134 | event_name = used_timeline.get("event/"+str(next_idx)).resource_name 135 | 136 | hint_string = hint_string.format({"event_name":event_name, "timeline_name":timeline_name}) 137 | text = text.format({"__next_event__":hint_string}) 138 | 139 | 140 | __event_preview_label.text = text 141 | 142 | 143 | func __update_identation() -> void: 144 | var indentation_level:int = 0 145 | if event: 146 | indentation_level = event.event_indent_level 147 | set_indentation_level(indentation_level) 148 | 149 | 150 | func _notification(what): 151 | match what: 152 | NOTIFICATION_THEME_CHANGED, NOTIFICATION_ENTER_TREE: 153 | var none := StyleBoxEmpty.new() 154 | event_button.add_stylebox_override("normal", none) 155 | event_button.add_stylebox_override("hover", get_stylebox("hover", "EventNode")) 156 | event_button.add_stylebox_override("pressed", get_stylebox("pressed", "EventNode")) 157 | event_button.add_stylebox_override("focus", get_stylebox("hover", "EventNode")) 158 | 159 | __header.get_child(0).set_deferred("rect_min_size", Vector2(get_constant("margin_left", "EventNode"),0)) 160 | 161 | var icon_bg = StyleBoxTexture.new() 162 | icon_bg.texture = get_icon("bg", "EventNode") 163 | __icon_container.add_stylebox_override("panel", icon_bg) 164 | 165 | __expand_button.add_icon_override("off", get_icon("unchecked", "EventNode")) 166 | __expand_button.add_icon_override("on", get_icon("checked", "EventNode")) 167 | 168 | __body.add_constant_override("margin_left", 50) 169 | 170 | var style = StyleBoxEmpty.new() 171 | style.content_margin_bottom = 3 172 | __bg.add_stylebox_override("panel", style) 173 | 174 | 175 | func _init(): 176 | name = "EventNode" 177 | size_flags_horizontal = SIZE_EXPAND_FILL 178 | rect_clip_content = true 179 | 180 | __indent_node = Control.new() 181 | 182 | __bg = PanelContainer.new() 183 | __bg.focus_mode = Control.FOCUS_NONE 184 | __bg.mouse_filter = Control.MOUSE_FILTER_IGNORE 185 | __bg.size_flags_horizontal = SIZE_EXPAND_FILL 186 | 187 | event_button = Button.new() 188 | event_button.toggle_mode = true 189 | event_button.focus_mode = Control.FOCUS_ALL 190 | event_button.mouse_filter = Control.MOUSE_FILTER_PASS 191 | event_button.name = "UIBehaviour" 192 | event_button.set_meta("event_node", self) 193 | event_button.connect("toggled", self, "_on_event_button_toggled") 194 | 195 | var vb = VBoxContainer.new() 196 | vb.focus_mode = Control.FOCUS_NONE 197 | vb.mouse_filter = Control.MOUSE_FILTER_IGNORE 198 | 199 | __header = HBoxContainer.new() 200 | __header.name = "Header" 201 | __header.focus_mode = Control.FOCUS_NONE 202 | __header.mouse_filter = Control.MOUSE_FILTER_IGNORE 203 | 204 | __body = MarginContainer.new() 205 | __body.name = "Body" 206 | __body.focus_mode = Control.FOCUS_NONE 207 | __body.mouse_filter = Control.MOUSE_FILTER_IGNORE 208 | 209 | __expand_button = CheckButton.new() 210 | __expand_button.visible = false 211 | __expand_button.connect("toggled", self, "_on_expand_toggled") 212 | __expand_button.set_pressed_no_signal(true) 213 | 214 | __icon_container = PanelContainer.new() 215 | __icon_node = TextureRect.new() 216 | __icon_node.name = "Icon" 217 | __icon_node.expand = true 218 | __icon_node.rect_min_size = Vector2(32,32) 219 | __icon_node.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED 220 | __icon_container.add_child(__icon_node) 221 | 222 | __event_label = Label.new() 223 | __event_label.mouse_filter = Control.MOUSE_FILTER_IGNORE 224 | __event_label.focus_mode = Control.FOCUS_NONE 225 | 226 | __event_preview_label = Label.new() 227 | __event_preview_label.mouse_filter = Control.MOUSE_FILTER_IGNORE 228 | __event_preview_label.focus_mode = Control.FOCUS_NONE 229 | 230 | var c := Control.new() 231 | c.focus_mode = Control.FOCUS_NONE 232 | c.mouse_filter = Control.MOUSE_FILTER_IGNORE 233 | __header.add_child(c) 234 | 235 | var hb := HBoxContainer.new() 236 | hb.focus_mode = Control.FOCUS_NONE 237 | hb.mouse_filter = Control.MOUSE_FILTER_IGNORE 238 | __header.add_child(hb) 239 | __header.add_child(__expand_button) 240 | 241 | __body.add_child(VBoxContainer.new()) 242 | 243 | vb.add_child(__header) 244 | vb.add_child(__body) 245 | 246 | __bg.add_child(event_button) 247 | __bg.add_child(vb) 248 | 249 | add_child(__indent_node) 250 | add_child(__bg) 251 | 252 | add_node_at_header(__icon_container) 253 | add_node_at_header(__event_label) 254 | # add_node_at_header(VSeparator.new()) 255 | add_node_at_header(__event_preview_label) 256 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/event_node/event_popup_menu.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends PopupMenu 3 | 4 | ## This serves as a builder for the popup menu 5 | ## Its behaviour is inside the timeline editor, since 6 | ## this node doesn't need its context at all. 7 | 8 | # ItemType and item generation have a 1:1 relationship 9 | # Use get_item_index(ItemType) to get the idx of that item 10 | enum ItemType { 11 | TITLE, 12 | EDIT, 13 | DUPLICATE, 14 | REMOVE, 15 | HELP, 16 | MOVE_UP, 17 | MOVE_DOWN, 18 | } 19 | 20 | var used_event:Resource setget set_event 21 | var shortcuts = load("res://addons/event_system_plugin/core/shortcuts.gd") 22 | 23 | func _enter_tree() -> void: 24 | var remove_shortcut = shortcuts.get_shortcut("remove") 25 | var duplicate_shortcut = shortcuts.get_shortcut("duplicate") 26 | 27 | add_separator("{EventName}", ItemType.TITLE) 28 | add_icon_item(get_icon("Edit", "EditorIcons"), "Edit in Inspector", ItemType.EDIT) 29 | 30 | add_shortcut(duplicate_shortcut, ItemType.DUPLICATE) 31 | set_item_icon(get_item_index(ItemType.DUPLICATE), get_icon("ActionCopy", "EditorIcons")) 32 | set_item_text(get_item_index(ItemType.DUPLICATE), "Duplicate") 33 | 34 | add_shortcut(remove_shortcut, ItemType.REMOVE) 35 | set_item_icon(get_item_index(ItemType.REMOVE), get_icon("Remove", "EditorIcons")) 36 | set_item_text(get_item_index(ItemType.REMOVE), "Remove") 37 | 38 | 39 | add_icon_item(get_icon("Help", "EditorIcons"), "Documentation", ItemType.HELP) 40 | add_separator() 41 | add_icon_item(get_icon("ArrowUp", "EditorIcons"), "Move up", ItemType.MOVE_UP) 42 | add_icon_item(get_icon("ArrowDown", "EditorIcons"), "Move down", ItemType.MOVE_DOWN) 43 | 44 | get_stylebox("panel").set("bg_color", get_color("base_color", "Editor")) 45 | add_color_override('font_color_hover', get_color("accent_color", "Editor")) 46 | add_stylebox_override('hover', StyleBoxEmpty.new()) 47 | 48 | 49 | func set_title(title:String) -> void: 50 | set_item_text(get_item_index(ItemType.TITLE), title) 51 | 52 | 53 | func set_event(event:Resource) -> void: 54 | used_event = event 55 | var event_name:String = "{EventName}" 56 | if used_event: 57 | event_name = str(used_event.get("event_name")) 58 | set_title(event_name) 59 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/event_selector/event_selector.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends ConfirmationDialog 3 | 4 | signal event_selected(event, timeline_path) 5 | 6 | const TimelineDisplayer = preload("res://addons/event_system_plugin/nodes/editor/timeline_displayer.gd") 7 | const TimelineList = preload("res://addons/event_system_plugin/nodes/editor/timeline_list.gd") 8 | const TimelineClass = preload("res://addons/event_system_plugin/resources/timeline_class/timeline_class.gd") 9 | const EvManager = preload("res://addons/event_system_plugin/nodes/event_manager/event_manager.gd") 10 | 11 | export(NodePath) var displayer_path:NodePath 12 | export(NodePath) var list_path:NodePath 13 | onready var timeline_displayer:TimelineDisplayer = get_node(displayer_path) as TimelineDisplayer 14 | onready var timeline_list:TimelineList = get_node(list_path) as TimelineList 15 | 16 | var last_selected_item:Node = null 17 | var timeline_name:String = "" 18 | var button_group = ButtonGroup.new() 19 | var edited_node:EvManager 20 | var edited_timeline:TimelineClass 21 | var event_summoner:Resource = null 22 | 23 | func _notification(what): 24 | match what: 25 | NOTIFICATION_POPUP_HIDE: 26 | if not visible: 27 | set_deferred("timeline_name", "") 28 | set_deferred("used_timeline", null) 29 | 30 | NOTIFICATION_POST_POPUP: 31 | if Engine.editor_hint: 32 | edited_node = Engine.get_meta("EventSystem").timeline_editor._edited_node 33 | edited_timeline = Engine.get_meta("EventSystem").timeline_editor._edited_sequence 34 | 35 | timeline_list.node = edited_node 36 | timeline_list.list_timelines() 37 | build_timeline(edited_timeline) 38 | 39 | NOTIFICATION_POST_ENTER_TREE: 40 | theme = load("res://addons/event_system_plugin/assets/themes/timeline_editor.tres") 41 | 42 | 43 | func _ready() -> void: 44 | timeline_displayer.connect("event_node_added", self, "_on_event_node_added") 45 | button_group.connect("pressed", self, "_on_event_node_pressed") 46 | timeline_list.connect("item_selected", self, "_timeline_selected") 47 | 48 | 49 | func build_timeline(timeline) -> void: 50 | edited_timeline = timeline 51 | timeline_displayer.load_timeline(timeline) 52 | 53 | 54 | func get_selected_event() -> Resource: 55 | var selected_event:Resource 56 | 57 | if is_instance_valid(last_selected_item): 58 | selected_event = last_selected_item.get("event") 59 | 60 | return selected_event 61 | 62 | 63 | func _get_current() -> String: 64 | var current:String = "" 65 | var selected_id:int = timeline_list.get_selected_id() 66 | 67 | if selected_id >= 0 && selected_id < timeline_list.get_item_count(): 68 | current = timeline_list.get_item_text(selected_id) 69 | 70 | return current 71 | 72 | 73 | func _timeline_selected(_index:int) -> void: 74 | var current := _get_current() 75 | 76 | if current != "": 77 | var timeline = edited_node.get_timeline(current) 78 | build_timeline(timeline) 79 | 80 | 81 | func _on_event_node_added(event_node) -> void: 82 | event_node.set_button_group(button_group) 83 | 84 | 85 | func _on_event_node_pressed(button:Button) -> void: 86 | last_selected_item = button.get_meta("event_node") 87 | 88 | 89 | func _on_ConfirmationDialog_confirmed(): 90 | var event = get_selected_event() 91 | var event_idx = edited_timeline.get_event_idx(event) 92 | var current_timeline = _get_current() 93 | 94 | emit_signal("event_selected", event_idx, current_timeline) 95 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/event_selector/event_selector.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=2] 2 | 3 | [ext_resource path="res://addons/event_system_plugin/nodes/editor/event_selector/event_selector.gd" type="Script" id=1] 4 | [ext_resource path="res://addons/event_system_plugin/nodes/editor/timeline_list.gd" type="Script" id=2] 5 | [ext_resource path="res://addons/event_system_plugin/nodes/editor/timeline_displayer.gd" type="Script" id=3] 6 | [ext_resource path="res://addons/event_system_plugin/assets/themes/timeline_editor.tres" type="Theme" id=4] 7 | 8 | [node name="ConfirmationDialog" type="ConfirmationDialog"] 9 | anchor_right = 1.0 10 | anchor_bottom = 1.0 11 | rect_min_size = Vector2( 150, 52.5 ) 12 | theme = ExtResource( 4 ) 13 | window_title = "Event Selector" 14 | script = ExtResource( 1 ) 15 | __meta__ = { 16 | "_edit_use_anchors_": false 17 | } 18 | displayer_path = NodePath("VBoxContainer/ScrollContainer/TimelineDisplayer") 19 | list_path = NodePath("VBoxContainer/HBoxContainer/OptionButton") 20 | 21 | [node name="VBoxContainer" type="VBoxContainer" parent="."] 22 | anchor_right = 1.0 23 | anchor_bottom = 1.0 24 | margin_left = 8.0 25 | margin_top = 8.0 26 | margin_right = -8.0 27 | margin_bottom = -36.0 28 | __meta__ = { 29 | "_edit_use_anchors_": false 30 | } 31 | 32 | [node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] 33 | margin_right = 1008.0 34 | margin_bottom = 20.0 35 | 36 | [node name="Label" type="Label" parent="VBoxContainer/HBoxContainer"] 37 | margin_top = 3.0 38 | margin_right = 152.0 39 | margin_bottom = 17.0 40 | text = "Please, select an event:" 41 | 42 | [node name="OptionButton" type="OptionButton" parent="VBoxContainer/HBoxContainer"] 43 | margin_left = 156.0 44 | margin_right = 1008.0 45 | margin_bottom = 20.0 46 | size_flags_horizontal = 3 47 | script = ExtResource( 2 ) 48 | __meta__ = { 49 | "_edit_use_anchors_": false 50 | } 51 | 52 | [node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer"] 53 | margin_top = 24.0 54 | margin_right = 1008.0 55 | margin_bottom = 556.0 56 | size_flags_vertical = 3 57 | 58 | [node name="TimelineDisplayer" type="VBoxContainer" parent="VBoxContainer/ScrollContainer"] 59 | margin_right = 1008.0 60 | margin_bottom = 532.0 61 | rect_min_size = Vector2( 128, 32 ) 62 | size_flags_horizontal = 3 63 | size_flags_vertical = 3 64 | script = ExtResource( 3 ) 65 | 66 | [connection signal="confirmed" from="." to="." method="_on_ConfirmationDialog_confirmed"] 67 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/flow_container.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Container 3 | 4 | class _LineData: 5 | var child_count:int = 0 6 | var min_line_height:int = 0 7 | var min_line_length:int = 0 8 | var stretch_avail:int = 0 9 | var stretch_ratio_total:float = 0 10 | 11 | export(int) var hseparation = 1 setget set_h_separation 12 | export(int) var vseparation = 1 setget set_v_separation 13 | export(bool) var vertical:bool = false 14 | 15 | var cached_size:int = 0 16 | var cached_line_count:int = 0 17 | 18 | 19 | func set_h_separation(value:int) -> void: 20 | hseparation = value 21 | add_constant_override("hseparation", value) 22 | property_list_changed_notify() 23 | queue_sort() 24 | 25 | 26 | func set_v_separation(value:int) -> void: 27 | vseparation = value 28 | add_constant_override("vseparation", value) 29 | property_list_changed_notify() 30 | queue_sort() 31 | 32 | 33 | func _resort() -> void: 34 | var separation_horizontal:int = get_constant("hseparation") 35 | var separation_vertical:int = get_constant("vseparation") 36 | 37 | # Not implemented in 3.4 38 | # var rtl = is_layout_rtl() 39 | var rtl = false 40 | 41 | var children_minsize_cache = {} 42 | 43 | var lines_data = [] 44 | 45 | var ofs:Vector2; 46 | var line_height:int = 0; 47 | var line_length:int = 0; 48 | var line_stretch_ratio_total:float = 0; 49 | var current_container_size:int = get_rect().size.y if vertical else get_rect().size.x 50 | var children_in_current_line:int = 0 51 | 52 | # First pass for line wrapping and minimum size calculation. 53 | for i in get_child_count(): 54 | var child:Control = get_child(i) as Control 55 | if (!child or !child.is_visible_in_tree()): 56 | continue 57 | 58 | if (child.is_set_as_toplevel()): 59 | continue 60 | 61 | var child_msc:Vector2 = child.get_combined_minimum_size() 62 | 63 | if (vertical): # /* Vertical */ 64 | if (children_in_current_line > 0): 65 | ofs.y += separation_vertical; 66 | 67 | if (ofs.y + child_msc.y > current_container_size): 68 | line_length = ofs.y - separation_vertical; 69 | var line_data = _LineData.new() 70 | line_data.child_count = children_in_current_line 71 | line_data.min_line_height = line_height 72 | line_data.min_line_length = line_length 73 | line_data.stretch_avail = current_container_size - line_length 74 | line_data.stretch_ratio_total = line_stretch_ratio_total 75 | lines_data.push_back(line_data) 76 | 77 | # Move in new column (vertical line). 78 | ofs.x += line_height + separation_horizontal; 79 | ofs.y = 0; 80 | line_height = 0; 81 | line_stretch_ratio_total = 0; 82 | children_in_current_line = 0; 83 | 84 | line_height = max(line_height, child_msc.x); 85 | if (child.get_v_size_flags() & SIZE_EXPAND): 86 | line_stretch_ratio_total += child.get_stretch_ratio() 87 | 88 | ofs.y += child_msc.y; 89 | 90 | else: # /* HORIZONTAL */ 91 | if (children_in_current_line > 0): 92 | ofs.x += separation_horizontal 93 | 94 | if (ofs.x + child_msc.x > current_container_size): 95 | line_length = ofs.x - separation_horizontal; 96 | var line_data = _LineData.new() 97 | line_data.child_count = children_in_current_line 98 | line_data.min_line_height = line_height 99 | line_data.min_line_length = line_length 100 | line_data.stretch_avail = current_container_size - line_length 101 | line_data.stretch_ratio_total = line_stretch_ratio_total 102 | lines_data.push_back(line_data) 103 | 104 | # Move in new line. 105 | ofs.y += line_height + separation_vertical; 106 | ofs.x = 0; 107 | line_height = 0; 108 | line_stretch_ratio_total = 0; 109 | children_in_current_line = 0; 110 | 111 | 112 | line_height = max(line_height, child_msc.y); 113 | if (child.get_h_size_flags() & SIZE_EXPAND): 114 | line_stretch_ratio_total += child.get_stretch_ratio() 115 | 116 | ofs.x += child_msc.x 117 | 118 | children_minsize_cache[child] = child_msc; 119 | children_in_current_line += 1 120 | 121 | line_length = (ofs.y) if vertical else (ofs.x) 122 | 123 | var ld:_LineData = _LineData.new() 124 | ld.child_count = children_in_current_line 125 | ld.min_line_length = line_height 126 | ld.min_line_length = line_length 127 | ld.stretch_avail = current_container_size - line_length 128 | ld.stretch_ratio_total = line_stretch_ratio_total 129 | lines_data.push_back(ld) 130 | 131 | # Second pass for in-line expansion and alignment. 132 | 133 | var current_line_idx = 0 134 | var child_idx_in_line = 0 135 | 136 | ofs.x = 0 137 | ofs.y = 0 138 | 139 | for i in get_child_count(): 140 | var child:Control = get_child(i) as Control 141 | if (!child or !child.is_visible_in_tree()): 142 | continue 143 | 144 | if (child.is_set_as_toplevel()): 145 | continue 146 | 147 | var child_size:Vector2 = children_minsize_cache[child]; 148 | 149 | var line_data:_LineData = lines_data[current_line_idx] 150 | if (child_idx_in_line >= lines_data[current_line_idx].child_count): 151 | current_line_idx += 1; 152 | child_idx_in_line = 0; 153 | if (vertical): 154 | ofs.x += line_data.min_line_height + separation_horizontal 155 | ofs.y = 0 156 | else: 157 | ofs.x = 0 158 | ofs.y += line_data.min_line_height + separation_vertical 159 | 160 | line_data = lines_data[current_line_idx] 161 | 162 | if (vertical): # /* VERTICAL */ 163 | if (child.get_h_size_flags() & (SIZE_FILL | SIZE_SHRINK_CENTER | SIZE_SHRINK_END)): 164 | child_size.x = line_data.min_line_height; 165 | 166 | if (child.get_v_size_flags() & SIZE_EXPAND): 167 | var stretch:int = line_data.stretch_avail * child.get_stretch_ratio() / line_data.stretch_ratio_total 168 | child_size.y += stretch; 169 | 170 | 171 | else: # /* HORIZONTAL */ 172 | if (child.get_v_size_flags() & (SIZE_FILL | SIZE_SHRINK_CENTER | SIZE_SHRINK_END)): 173 | child_size.y = line_data.min_line_height; 174 | 175 | if (child.get_h_size_flags() & SIZE_EXPAND): 176 | var stretch:int = line_data.stretch_avail * child.get_stretch_ratio() / line_data.stretch_ratio_total; 177 | child_size.x += stretch 178 | 179 | 180 | var child_rect:Rect2 = Rect2(ofs, child_size) 181 | if (rtl): 182 | child_rect.position.x = get_rect().size.x - child_rect.position.x - child_rect.size.x 183 | 184 | fit_child_in_rect(child, child_rect); 185 | 186 | if (vertical): # /* VERTICAL */ 187 | ofs.y += child_size.y + separation_vertical; 188 | else: # /* HORIZONTAL */ 189 | ofs.x += child_size.x + separation_horizontal; 190 | 191 | child_idx_in_line += 1 192 | 193 | cached_size = (ofs.x if vertical else ofs.y) + line_height; 194 | cached_line_count = lines_data.size(); 195 | 196 | 197 | func _get_minimum_size() -> Vector2: 198 | var minimum:Vector2 = Vector2() 199 | 200 | for i in get_child_count(): 201 | var child:Control = get_child(i) as Control 202 | 203 | if (!child or !child.is_visible_in_tree()): 204 | continue 205 | 206 | if (child.is_set_as_toplevel()): 207 | continue 208 | 209 | var size:Vector2 = child.get_combined_minimum_size() 210 | 211 | if (vertical): # /* VERTICAL */ 212 | minimum.y = max(minimum.y, size.y); 213 | minimum.x = cached_size; 214 | 215 | else: # /* HORIZONTAL */ 216 | minimum.x = max(minimum.x, size.x); 217 | minimum.y = cached_size; 218 | 219 | return minimum; 220 | 221 | 222 | func _notification(p_what:int) -> void: 223 | match (p_what): 224 | NOTIFICATION_SORT_CHILDREN: 225 | _resort(); 226 | minimum_size_changed() 227 | 228 | NOTIFICATION_THEME_CHANGED: 229 | minimum_size_changed() 230 | 231 | NOTIFICATION_TRANSLATION_CHANGED: 232 | queue_sort() 233 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/playground/event_manager_demo.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=30 format=2] 2 | 3 | [ext_resource path="res://addons/event_system_plugin/nodes/event_manager/event_manager.gd" type="Script" id=1] 4 | [ext_resource path="res://addons/event_system_plugin/resources/timeline_class/timeline_class.gd" type="Script" id=2] 5 | [ext_resource path="res://addons/event_system_plugin/events/call_from.gd" type="Script" id=3] 6 | [ext_resource path="res://addons/event_system_plugin/events/end_timeline.gd" type="Script" id=4] 7 | [ext_resource path="res://addons/event_system_plugin/events/set.gd" type="Script" id=5] 8 | [ext_resource path="res://addons/event_system_plugin/events/hide.gd" type="Script" id=6] 9 | [ext_resource path="res://addons/event_system_plugin/events/wait.gd" type="Script" id=7] 10 | [ext_resource path="res://addons/event_system_plugin/events/goto.gd" type="Script" id=8] 11 | [ext_resource path="res://addons/event_system_plugin/events/condition.gd" type="Script" id=9] 12 | [ext_resource path="res://addons/event_system_plugin/events/emit_signal.gd" type="Script" id=10] 13 | [ext_resource path="res://addons/event_system_plugin/events/show.gd" type="Script" id=11] 14 | [ext_resource path="res://addons/event_system_plugin/events/comment.gd" type="Script" id=12] 15 | 16 | [sub_resource type="GDScript" id=3] 17 | script/source = "extends Node 18 | 19 | var test = true 20 | 21 | func d_print(arg): 22 | print(arg) 23 | 24 | 25 | func _on_EventManager_event_started(event): 26 | prints(\"start\",event) 27 | 28 | 29 | func _on_EventManager_event_finished(event): 30 | print(\"finish\", event) 31 | 32 | 33 | func _on_EventManager_timeline_started(timeline_resource): 34 | prints(\"tmln start\",timeline_resource) 35 | 36 | 37 | func _on_EventManager_timeline_finished(timeline_resource): 38 | prints(\"tmln end\",timeline_resource) 39 | " 40 | 41 | [sub_resource type="Resource" id=7] 42 | resource_name = "Call" 43 | script = ExtResource( 3 ) 44 | continue_at_end = true 45 | method = "d_print" 46 | args = [ "working" ] 47 | event_node_path = NodePath("") 48 | event_subevents_quantity = 0 49 | 50 | [sub_resource type="Resource" id=8] 51 | resource_name = "Emit Signal" 52 | script = ExtResource( 10 ) 53 | continue_at_end = true 54 | data = "" 55 | event_node_path = NodePath("") 56 | event_subevents_quantity = 0 57 | 58 | [sub_resource type="Resource" id=9] 59 | resource_name = "Hide" 60 | script = ExtResource( 6 ) 61 | continue_at_end = true 62 | method = "set" 63 | args = [ "visible", false ] 64 | event_node_path = NodePath("") 65 | event_subevents_quantity = 0 66 | 67 | [sub_resource type="Resource" id=10] 68 | resource_name = "Set" 69 | script = ExtResource( 5 ) 70 | continue_at_end = true 71 | method = "set" 72 | args = [ "", "" ] 73 | variable_name = "" 74 | variable_value = "" 75 | event_node_path = NodePath("") 76 | event_subevents_quantity = 0 77 | 78 | [sub_resource type="Resource" id=11] 79 | resource_name = "Show" 80 | script = ExtResource( 11 ) 81 | continue_at_end = true 82 | method = "set" 83 | args = [ "visible", true ] 84 | event_node_path = NodePath("") 85 | event_subevents_quantity = 0 86 | 87 | [sub_resource type="Resource" id=12] 88 | resource_name = "Comment" 89 | script = ExtResource( 12 ) 90 | continue_at_end = true 91 | text = "" 92 | event_node_path = NodePath("") 93 | event_subevents_quantity = 0 94 | 95 | [sub_resource type="Resource" id=13] 96 | resource_name = "End Timeline" 97 | script = ExtResource( 4 ) 98 | continue_at_end = true 99 | event_node_path = NodePath("") 100 | event_subevents_quantity = 0 101 | 102 | [sub_resource type="Resource" id=14] 103 | resource_name = "Condition" 104 | script = ExtResource( 9 ) 105 | continue_at_end = true 106 | condition = "" 107 | event_node_path = NodePath("") 108 | event_subevents_quantity = 0 109 | 110 | [sub_resource type="Resource" id=15] 111 | resource_name = "Wait" 112 | script = ExtResource( 7 ) 113 | continue_at_end = true 114 | wait_time = 0.0 115 | event_node_path = NodePath("") 116 | event_subevents_quantity = 0 117 | 118 | [sub_resource type="Resource" id=16] 119 | resource_name = "Go to" 120 | script = ExtResource( 8 ) 121 | continue_at_end = true 122 | next_event = "3;Test timeline" 123 | event_node_path = NodePath("") 124 | event_subevents_quantity = 0 125 | 126 | [sub_resource type="Resource" id=5] 127 | resource_name = "Timeline" 128 | script = ExtResource( 2 ) 129 | event/0 = SubResource( 7 ) 130 | event/1 = SubResource( 8 ) 131 | event/2 = SubResource( 9 ) 132 | event/3 = SubResource( 10 ) 133 | event/4 = SubResource( 11 ) 134 | event/5 = SubResource( 12 ) 135 | event/6 = SubResource( 13 ) 136 | event/7 = SubResource( 14 ) 137 | event/8 = SubResource( 15 ) 138 | event/9 = SubResource( 16 ) 139 | 140 | [sub_resource type="Resource" id=17] 141 | resource_name = "Call" 142 | script = ExtResource( 3 ) 143 | continue_at_end = true 144 | method = "d_print" 145 | args = [ "hello" ] 146 | event_node_path = NodePath("") 147 | event_subevents_quantity = 0 148 | 149 | [sub_resource type="Resource" id=18] 150 | resource_name = "Go to" 151 | script = ExtResource( 8 ) 152 | continue_at_end = true 153 | next_event = "" 154 | event_node_path = NodePath("") 155 | event_subevents_quantity = 0 156 | 157 | [sub_resource type="Resource" id=6] 158 | resource_name = "Timeline" 159 | script = ExtResource( 2 ) 160 | event/0 = SubResource( 17 ) 161 | event/1 = SubResource( 18 ) 162 | 163 | [sub_resource type="Resource" id=19] 164 | resource_name = "Call" 165 | script = ExtResource( 3 ) 166 | continue_at_end = true 167 | method = "d_print" 168 | args = [ "it works" ] 169 | event_node_path = NodePath("") 170 | event_subevents_quantity = 0 171 | 172 | [sub_resource type="Resource" id=20] 173 | resource_name = "Timeline" 174 | script = ExtResource( 2 ) 175 | event/0 = SubResource( 19 ) 176 | 177 | [node name="Node" type="Node"] 178 | script = SubResource( 3 ) 179 | 180 | [node name="EventManager" type="Node" parent="."] 181 | script = ExtResource( 1 ) 182 | event_node_fallback_path = NodePath("..") 183 | start_on_ready = true 184 | current_timeline = "debug" 185 | "timeline/Test timeline" = SubResource( 5 ) 186 | timeline/debug = SubResource( 6 ) 187 | timeline/test = SubResource( 20 ) 188 | 189 | [connection signal="event_finished" from="EventManager" to="." method="_on_EventManager_event_finished"] 190 | [connection signal="event_started" from="EventManager" to="." method="_on_EventManager_event_started"] 191 | [connection signal="timeline_finished" from="EventManager" to="." method="_on_EventManager_timeline_finished"] 192 | [connection signal="timeline_started" from="EventManager" to="." method="_on_EventManager_timeline_started"] 193 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/playground/in_game_editor.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [sub_resource type="GDScript" id=1] 4 | script/source = "extends Node 5 | 6 | var tml 7 | var editor:Control = load(\"res://addons/event_system_plugin/nodes/editor/timeline_editor.gd\").new() 8 | 9 | func _ready() -> void: 10 | add_child(editor) 11 | editor.set_margins_preset(Control.PRESET_WIDE) 12 | 13 | # if ResourceLoader.exists(\"test.tres\"): 14 | # tml = load(\"test.tres\") as Timeline 15 | 16 | if !tml: 17 | tml = Timeline.new() 18 | var cond = EventCondition.new() 19 | # cond.event_subevents_quantity = 1 20 | tml.add_event(cond) 21 | tml.add_event(Event.new()) 22 | tml.add_event(EventComment.new()) 23 | 24 | editor.timeline_displayer.connect(\"load_ended\", self, \"timeline_changed\") 25 | 26 | var node := EventManager.new() 27 | add_child(node) 28 | node.add_timeline(\"new timeline\", tml) 29 | # node.add_timeline(\"timeline 2\", tml2) 30 | editor.edit_node(node) 31 | $Label.raise() 32 | $Control.raise() 33 | tml.emit_changed() 34 | 35 | 36 | func timeline_changed(): 37 | $Label.text = get_string_tree() 38 | $Control.update() 39 | 40 | 41 | func _exit_tree() -> void: 42 | print(get_string_tree()) 43 | # assert(ResourceSaver.save(\"test.tres\", tml) == OK) 44 | 45 | 46 | func get_string_tree() -> String: 47 | var tree = \"\" 48 | for event in tml.get_events(): 49 | for i in event.event_indent_level: 50 | tree += \"- \" 51 | tree += event.event_name 52 | tree += \" | [{sub}] idx:{idx} \\n\".format({\"idx\":tml.get_event_idx(event), \"sub\":event.event_subevents_quantity}) 53 | 54 | return tree 55 | 56 | func _on_Button_pressed() -> void: 57 | editor.reload() 58 | 59 | 60 | func _on_Control_draw() -> void: 61 | var rect:Rect2 = editor.timeline_displayer.get_rect() 62 | rect.position = editor.timeline_displayer.rect_global_position 63 | $Control.draw_rect(rect, Color.red, false) 64 | 65 | 66 | func _on_Undo_pressed() -> void: 67 | var ur:UndoRedo = editor._get_undo_redo() 68 | if ur.has_undo(): 69 | ur.undo() 70 | 71 | 72 | func _on_Redo_pressed() -> void: 73 | var ur:UndoRedo = editor._get_undo_redo() 74 | if ur.has_redo(): 75 | ur.redo() 76 | " 77 | 78 | [sub_resource type="Animation" id=2] 79 | resource_name = "Nueva Animación" 80 | tracks/0/type = "value" 81 | tracks/0/path = NodePath(".:editor_description") 82 | tracks/0/interp = 1 83 | tracks/0/loop_wrap = true 84 | tracks/0/imported = false 85 | tracks/0/enabled = true 86 | tracks/0/keys = { 87 | "times": PoolRealArray( 0.1, 0.6 ), 88 | "transitions": PoolRealArray( 1, 1 ), 89 | "update": 1, 90 | "values": [ "", "asdfasdasda" ] 91 | } 92 | 93 | [sub_resource type="Animation" id=3] 94 | resource_name = "Nueva Animación (2)" 95 | 96 | [node name="Playground" type="Node"] 97 | script = SubResource( 1 ) 98 | __meta__ = { 99 | "_editor_description_": "asdfasdasda" 100 | } 101 | 102 | [node name="AnimationPlayer" type="AnimationPlayer" parent="."] 103 | "anims/Nueva Animación" = SubResource( 2 ) 104 | "anims/Nueva Animación (2)" = SubResource( 3 ) 105 | 106 | [node name="Label" type="Label" parent="."] 107 | margin_left = 743.0 108 | margin_top = 3.0 109 | margin_right = 1020.0 110 | margin_bottom = 231.0 111 | grow_horizontal = 0 112 | autowrap = true 113 | __meta__ = { 114 | "_edit_use_anchors_": false 115 | } 116 | 117 | [node name="Control" type="Control" parent="."] 118 | anchor_right = 1.0 119 | anchor_bottom = 1.0 120 | mouse_filter = 2 121 | __meta__ = { 122 | "_edit_use_anchors_": false 123 | } 124 | 125 | [node name="Button" type="Button" parent="Control"] 126 | margin_left = 778.0 127 | margin_top = 557.0 128 | margin_right = 942.0 129 | margin_bottom = 587.0 130 | text = "reset" 131 | __meta__ = { 132 | "_edit_use_anchors_": false 133 | } 134 | 135 | [node name="Undo" type="Button" parent="Control"] 136 | margin_left = 651.0 137 | margin_top = 562.0 138 | margin_right = 697.0 139 | margin_bottom = 582.0 140 | text = "Undo" 141 | __meta__ = { 142 | "_edit_use_anchors_": false 143 | } 144 | 145 | [node name="Redo" type="Button" parent="Control"] 146 | margin_left = 712.0 147 | margin_top = 562.0 148 | margin_right = 758.0 149 | margin_bottom = 582.0 150 | text = "Redo" 151 | __meta__ = { 152 | "_edit_use_anchors_": false 153 | } 154 | 155 | [connection signal="draw" from="Control" to="." method="_on_Control_draw"] 156 | [connection signal="pressed" from="Control/Button" to="." method="_on_Button_pressed"] 157 | [connection signal="pressed" from="Control/Undo" to="." method="_on_Undo_pressed"] 158 | [connection signal="pressed" from="Control/Redo" to="." method="_on_Redo_pressed"] 159 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/subtimeline.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends PanelContainer 3 | 4 | class TitleBar extends PanelContainer: 5 | signal toggled(pressed) 6 | 7 | var bar:HBoxContainer 8 | var collapse_button:CheckBox 9 | 10 | func _gui_input(event: InputEvent) -> void: 11 | if event is InputEventMouseButton and event.is_pressed(): 12 | collapse_button.grab_focus() 13 | collapse_button.grab_click_focus() 14 | 15 | 16 | func _toggle(button_pressed:bool) -> void: 17 | emit_signal("toggled", button_pressed) 18 | 19 | 20 | func _enter_tree() -> void: 21 | collapse_button.add_icon_override("unchecked", get_icon("Forward", "EditorIcons")) 22 | collapse_button.add_icon_override("checked", get_icon("Collapse", "EditorIcons")) 23 | add_stylebox_override("panel", get_stylebox("panel_odd", "TabContainer")) 24 | 25 | 26 | func _init() -> void: 27 | bar = HBoxContainer.new() 28 | bar.mouse_filter = Control.MOUSE_FILTER_IGNORE 29 | bar.focus_mode = Control.FOCUS_NONE 30 | bar.size_flags_horizontal = SIZE_EXPAND_FILL 31 | bar.size_flags_vertical = SIZE_EXPAND_FILL 32 | bar.rect_clip_content = true 33 | 34 | collapse_button = CheckBox.new() 35 | collapse_button.set_pressed_no_signal(true) 36 | bar.add_child(collapse_button) 37 | add_child(bar) 38 | 39 | collapse_button.connect("toggled", self, "_toggle") 40 | 41 | 42 | func generate_previews(for_these_events:Array) -> void: 43 | for child in bar.get_children(): 44 | if child == collapse_button: 45 | continue 46 | child.queue_free() 47 | 48 | var holder = HBoxContainer.new() 49 | holder.focus_mode = Control.FOCUS_NONE 50 | holder.mouse_filter = Control.MOUSE_FILTER_IGNORE 51 | bar.add_child(holder) 52 | for event in for_these_events: 53 | var t_node := TextureRect.new() 54 | t_node.focus_mode = Control.FOCUS_NONE 55 | t_node.mouse_filter = Control.MOUSE_FILTER_IGNORE 56 | t_node.rect_min_size = Vector2(16,16) 57 | t_node.expand = true 58 | t_node.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED 59 | t_node.texture = event.get("event_icon") as Texture 60 | holder.add_child(t_node) 61 | 62 | 63 | var unfolded_container:TabContainer 64 | var body:VBoxContainer 65 | var title_bar:TitleBar 66 | var preview:Resource 67 | 68 | func add_timeline_and_get_node(timeline:Resource) -> Control: 69 | var TimelineDisplayer = load("res://addons/event_system_plugin/nodes/editor/timeline_displayer.gd") 70 | var timeline_displayer:Control = TimelineDisplayer.new() 71 | unfolded_container.add_child(timeline_displayer) 72 | 73 | if not preview: 74 | preview = timeline 75 | 76 | if unfolded_container.get_child_count() > 1: 77 | unfolded_container.tabs_visible = true 78 | 79 | timeline_displayer.set("last_used_timeline", timeline) 80 | timeline_displayer.call_deferred("load_timeline", timeline) 81 | timeline.connect("changed", timeline_displayer, "reload") 82 | return timeline_displayer 83 | 84 | 85 | func _set_subtimeline_visible(_visible:bool) -> void: 86 | unfolded_container.visible = _visible 87 | 88 | var events := [] 89 | if not _visible: 90 | events = preview.get_events() 91 | title_bar.generate_previews(events) 92 | 93 | 94 | func _enter_tree() -> void: 95 | body.add_constant_override("separation", 0) 96 | 97 | 98 | func _init() -> void: 99 | name = "SubtimelineContainer" 100 | mouse_filter = Control.MOUSE_FILTER_IGNORE 101 | focus_mode = Control.FOCUS_NONE 102 | 103 | unfolded_container = TabContainer.new() 104 | title_bar = TitleBar.new() 105 | body = VBoxContainer.new() 106 | body.mouse_filter = Control.MOUSE_FILTER_IGNORE 107 | body.add_child(title_bar) 108 | body.add_child(unfolded_container) 109 | add_child(body) 110 | 111 | unfolded_container.tabs_visible = false 112 | 113 | title_bar.connect("toggled", self, "_set_subtimeline_visible") 114 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/timeline_displayer.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends VBoxContainer 3 | 4 | const EventClass = preload("res://addons/event_system_plugin/resources/event_class/event_class.gd") 5 | const TimelineClass = preload("res://addons/event_system_plugin/resources/timeline_class/timeline_class.gd") 6 | 7 | signal event_node_added(event_node) 8 | signal load_started 9 | signal load_ended 10 | 11 | const EventNode = preload("res://addons/event_system_plugin/nodes/editor/event_node/event_node.gd") 12 | const DEFAULT_MIN_SIZE = Vector2(128, 32) 13 | 14 | var data := [] 15 | var loading := false 16 | 17 | # Hint for editor 18 | var last_used_timeline:Resource = null 19 | 20 | 21 | func load_timeline(timeline) -> void: 22 | remove_all_displayed_events() 23 | data = timeline.get_events() 24 | last_used_timeline = timeline 25 | update_view() 26 | 27 | 28 | func is_loading() -> bool: 29 | return loading 30 | 31 | 32 | func update_view() -> void: 33 | _notify_load_started() 34 | 35 | for event_idx in data.size(): 36 | var event = data[event_idx] 37 | var event_node = _get_event_node(event) 38 | event_node.set("timeline",last_used_timeline) 39 | event_node.set("idx", event_idx) 40 | emit_signal("event_node_added", event_node) 41 | add_child(event_node) 42 | event_node.call_deferred("update_values") 43 | 44 | update_indentation() 45 | _notify_load_ended() 46 | 47 | func update_indentation() -> void: 48 | last_used_timeline.update_structure() 49 | 50 | 51 | func remove_all_displayed_events() -> void: 52 | for child in get_children(): 53 | child.queue_free() 54 | 55 | 56 | func reload() -> void: 57 | remove_all_displayed_events() 58 | load_timeline(last_used_timeline) 59 | 60 | 61 | func _get_event_node(event:EventClass) -> EventNode: 62 | if not event: 63 | return null 64 | 65 | var event_node:EventNode 66 | event_node = event.get("custom_event_node") as EventNode 67 | if event_node == null: 68 | event_node = EventNode.new() 69 | 70 | event_node.event = event 71 | return event_node 72 | 73 | 74 | func _notify_load_started() -> void: 75 | loading = true 76 | emit_signal("load_started") 77 | 78 | 79 | func _notify_load_ended() -> void: 80 | loading = false 81 | emit_signal("load_ended") 82 | queue_sort() 83 | 84 | 85 | func _init() -> void: 86 | mouse_filter = Control.MOUSE_FILTER_PASS 87 | size_flags_horizontal = SIZE_EXPAND_FILL 88 | size_flags_vertical = SIZE_EXPAND_FILL 89 | rect_min_size = DEFAULT_MIN_SIZE 90 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/timeline_drawer.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Control 3 | 4 | const TimelineDisplayer = preload("res://addons/event_system_plugin/nodes/editor/timeline_displayer.gd") 5 | const EventNode = preload("res://addons/event_system_plugin/nodes/editor/event_node/event_node.gd") 6 | 7 | var timeline_displayer:TimelineDisplayer setget set_timeline_displayer 8 | 9 | func set_timeline_displayer(displayer:TimelineDisplayer) -> void: 10 | if is_instance_valid(timeline_displayer): 11 | if timeline_displayer.is_connected("load_ended", self, "_load_ended"): 12 | timeline_displayer.disconnect("load_ended",self,"_load_ended") 13 | 14 | timeline_displayer = displayer 15 | 16 | if is_instance_valid(timeline_displayer): 17 | timeline_displayer.connect("load_ended", self, "_load_ended") 18 | 19 | 20 | func _displayer_draw() -> void: 21 | var child_size:int = timeline_displayer.get_children().size() 22 | var td = timeline_displayer # timeline_displayer is too long, and i'm too lazy 23 | for node in timeline_displayer.get_children(): 24 | node = node as Control 25 | if not node: 26 | continue 27 | # td.draw_line(node.rect_position, Vector2(0, node.rect_size.y), Color.red, 2) 28 | draw_rect(node.get_rect(), Color.red, false, 4) 29 | 30 | 31 | func _load_ended() -> void: 32 | update() 33 | 34 | func _init(): 35 | mouse_filter = Control.MOUSE_FILTER_IGNORE 36 | focus_mode = Control.FOCUS_NONE 37 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/timeline_editor.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends VBoxContainer 3 | 4 | const TimelineDisplayer = preload("res://addons/event_system_plugin/nodes/editor/timeline_displayer.gd") 5 | const EventNode = preload("res://addons/event_system_plugin/nodes/editor/event_node/event_node.gd") 6 | const CategoryManager = preload("res://addons/event_system_plugin/nodes/editor/category_manager.gd") 7 | const EventClass = preload("res://addons/event_system_plugin/resources/event_class/event_class.gd") 8 | const TimelineClass = preload("res://addons/event_system_plugin/resources/timeline_class/timeline_class.gd") 9 | const EventMenu = preload("res://addons/event_system_plugin/nodes/editor/event_node/event_popup_menu.gd") 10 | const TimelineList = preload("res://addons/event_system_plugin/nodes/editor/timeline_list.gd") 11 | const EventManagerClass = preload("res://addons/event_system_plugin/nodes/event_manager/event_manager.gd") 12 | 13 | enum { 14 | TOOL_NEW_TIMELINE, 15 | TOOL_DUPLICATE_TIMELINE, 16 | TOOL_RENAME_TIMELINE, 17 | TOOL_REMOVE_TIMELINE, 18 | TOOL_EDIT_RESOURCE 19 | } 20 | 21 | signal inspection_requested(resource) 22 | 23 | var shortcuts = load("res://addons/event_system_plugin/core/shortcuts.gd") 24 | 25 | var timeline_displayer:TimelineDisplayer 26 | var last_selected_event_node:EventNode 27 | var is_moving_event:bool = false 28 | 29 | var _sc:ScrollContainer 30 | var _event_menu:EventMenu 31 | var _edited_sequence:TimelineClass 32 | var _category_manager:CategoryManager 33 | var _timeline_list:TimelineList 34 | var _timeline_tools:MenuButton 35 | var _error_dialog:AcceptDialog 36 | var _error_label:Label 37 | var _name_dialog:ConfirmationDialog 38 | var _new_name_label:Label 39 | var _new_name_edit:LineEdit 40 | var _remove_dialog:ConfirmationDialog 41 | var _remove_label:Label 42 | var _info_label:Label 43 | 44 | var _renaming := false 45 | 46 | var _edited_node:EventManagerClass 47 | 48 | var __undo_redo:UndoRedo # Do not use thid directly, get its reference with _get_undo_redo 49 | var __group:ButtonGroup 50 | 51 | func set_undo_redo(value:UndoRedo) -> void: 52 | # Sets UndoRedo, but this object can leave leaked isntances so make sure to set it 53 | # with an external reference (aka Editor's UndoRedo). 54 | # To internal use of UndoRedo use _get_undo_redo instead. 55 | __undo_redo = value 56 | 57 | func edit(object:Object) -> void: 58 | if object is TimelineClass: 59 | _info_label.show() 60 | _info_label.text = "You're editing a single timeline. Some editor tools may not be enabled." 61 | 62 | _edited_node = null 63 | 64 | _timeline_list.node = null 65 | _timeline_list.list_timelines() 66 | _timeline_list.add_item(object.resource_name) 67 | _timeline_list.disabled = true 68 | 69 | _timeline_tools.disabled = true 70 | 71 | edit_timeline(object) 72 | 73 | if object is EventManagerClass: 74 | _info_label.hide() 75 | _timeline_list.disabled = false 76 | _timeline_tools.disabled = false 77 | edit_node(object) 78 | 79 | 80 | func edit_node(node:EventManagerClass) -> void: 81 | _edited_node = node 82 | _timeline_list.node = _edited_node 83 | _timeline_list.list_timelines() 84 | if _edited_node: 85 | if _get_current() == "": 86 | edit_timeline(null) 87 | return 88 | 89 | edit_timeline(_edited_node.get_timeline(_get_current())) 90 | 91 | 92 | func edit_timeline(sequence) -> void: 93 | _disconnect_edited_sequence_signals() 94 | 95 | _edited_sequence = sequence 96 | timeline_displayer.remove_all_displayed_events() 97 | if sequence: 98 | timeline_displayer.load_timeline(sequence) 99 | 100 | _connect_edited_sequence_signals() 101 | 102 | 103 | func edit_timeline_by_name(timeline_name:String) -> void: 104 | for idx in _timeline_list.get_item_count(): 105 | var item_name = _timeline_list.get_item_text(idx) 106 | if item_name == timeline_name: 107 | _timeline_list.select(idx) 108 | 109 | edit_timeline(_edited_node.get_timeline(_get_current())) 110 | 111 | 112 | func reload() -> void: 113 | timeline_displayer.call_deferred("load_timeline", _edited_sequence) 114 | 115 | 116 | func remove_event(event:EventClass, from_resource:TimelineClass) -> void: 117 | if event == null or from_resource == null: 118 | return 119 | 120 | var _UndoRedo:UndoRedo = _get_undo_redo() 121 | 122 | var parent_event_ref:WeakRef = event.event_subevent_from 123 | var parent_event:EventClass 124 | var old_value:int = 0 125 | var new_value:int = 0 126 | if parent_event_ref: 127 | parent_event = parent_event_ref.get_ref() as EventClass 128 | if parent_event: 129 | old_value = parent_event.event_subevents_quantity 130 | new_value = max(0, old_value-1) 131 | 132 | var event_idx:int = from_resource.get_event_idx(event) 133 | _UndoRedo.create_action("Remove event from timeline") 134 | _UndoRedo.add_do_method(from_resource, "erase_event", event) 135 | _UndoRedo.add_undo_method(from_resource, "insert_event", event, event_idx) 136 | 137 | if parent_event: 138 | _UndoRedo.add_do_property(parent_event, "event_subevents_quantity", new_value) 139 | _UndoRedo.add_undo_property(parent_event, "event_subevents_quantity", old_value) 140 | 141 | _UndoRedo.commit_action() 142 | 143 | 144 | func add_event(event:EventClass, at_position:int=-1, from_resource:Resource=_edited_sequence, as_subevent_of:EventClass=null) -> void: 145 | if not from_resource: 146 | return 147 | 148 | var _UndoRedo:UndoRedo = _get_undo_redo() 149 | 150 | var parent_event:EventClass = as_subevent_of 151 | var old_value:int = 0 152 | var new_value:int = 0 153 | if parent_event: 154 | old_value = parent_event.event_subevents_quantity 155 | new_value = old_value+1 156 | 157 | _UndoRedo.create_action("Add event %s"%event.event_name) 158 | if at_position < 0: 159 | _UndoRedo.add_do_method(from_resource, "add_event", event) 160 | else: 161 | _UndoRedo.add_do_method(from_resource, "insert_event", event, at_position) 162 | 163 | _UndoRedo.add_undo_method(from_resource, "erase_event", event) 164 | 165 | if parent_event: 166 | _UndoRedo.add_do_property(parent_event, "event_subevents_quantity", new_value) 167 | _UndoRedo.add_undo_property(parent_event, "event_subevents_quantity", old_value) 168 | 169 | _UndoRedo.commit_action() 170 | 171 | 172 | func move_event(event:EventClass, to:int, from_resource:TimelineClass=_edited_sequence, as_subevent_of:EventClass=null) -> void: 173 | if not from_resource: 174 | return 175 | 176 | var old_position:int = from_resource.get_event_idx(event) 177 | 178 | var _UndoRedo:UndoRedo = _get_undo_redo() 179 | 180 | _UndoRedo.create_action("Move event %s"%event.event_name) 181 | 182 | var old_parent:EventClass 183 | var new_parent:EventClass = as_subevent_of 184 | 185 | if event.event_subevent_from: 186 | old_parent = event.event_subevent_from.get_ref() as EventClass 187 | 188 | var old_value:int = 0 189 | var new_value:int = 0 190 | 191 | if !from_resource.event_is_subevent_of(event, new_parent): 192 | if old_parent: 193 | old_value = old_parent.event_subevents_quantity 194 | new_value = max(0, old_value-1) 195 | _UndoRedo.add_do_property(old_parent, "event_subevents_quantity", new_value) 196 | _UndoRedo.add_undo_property(old_parent, "event_subevents_quantity", old_value) 197 | 198 | if new_parent: 199 | old_value = new_parent.event_subevents_quantity 200 | new_value = old_value+1 201 | _UndoRedo.add_do_property(new_parent, "event_subevents_quantity", new_value) 202 | _UndoRedo.add_undo_property(new_parent, "event_subevents_quantity", old_value) 203 | 204 | if to < 0: 205 | if old_parent: 206 | old_value = old_parent.event_subevents_quantity 207 | new_value = max(0, old_value-1) 208 | _UndoRedo.add_do_property(old_parent, "event_subevents_quantity", new_value) 209 | _UndoRedo.add_undo_property(old_parent, "event_subevents_quantity", old_value) 210 | 211 | event.event_indent_level = 0 212 | 213 | _UndoRedo.add_do_method(from_resource, "move_event", event, to) 214 | _UndoRedo.add_undo_method(from_resource, "move_event", event, old_position) 215 | 216 | _UndoRedo.commit_action() 217 | 218 | 219 | func get_drag_data_fw(position, node): 220 | if node is EventNode: 221 | var event:EventClass = node.get("event") 222 | var timeline:TimelineClass = node.get("timeline") 223 | is_moving_event = true 224 | 225 | if not event: 226 | return null 227 | 228 | var _node = node.duplicate(0) 229 | 230 | _node.rect_size = Vector2.ZERO 231 | set_drag_preview(_node) 232 | var data = {} 233 | data["event"] = event 234 | 235 | return data 236 | 237 | 238 | var _separator_node:EventNode 239 | var _idx_hint:int = -1 240 | var _last_node:Node 241 | func can_drop_data_fw(position: Vector2, data, node:Control) -> bool: 242 | var event_data:EventClass 243 | 244 | if typeof(data) in [TYPE_OBJECT, TYPE_DICTIONARY]: 245 | event_data = data.get("event") 246 | if event_data == null: 247 | return false 248 | else: 249 | return false 250 | 251 | # if !is_instance_valid(_separator_node): 252 | # _generate_separator_node() 253 | # _separator_node.event = node.get("event") as EventClass 254 | # _separator_node.update_values() 255 | # 256 | # if node is EventNode: 257 | # var node_rect:Rect2 = node.get_rect() 258 | # var node_event = node.get("event") 259 | # 260 | # var pos = node.get_index() 261 | # if position.y > node_rect.size.y/2: 262 | # pos = node.get_index()+1 263 | # timeline_displayer.move_child(_separator_node, pos) 264 | 265 | _last_node = node 266 | # return node is TimelineDisplayer and event_data is EventClass 267 | return event_data is EventClass 268 | 269 | 270 | func drop_data_fw(position: Vector2, data, node) -> void: 271 | var event_data:EventClass = data.get("event") 272 | var subevent_of = null 273 | 274 | if node is EventNode: 275 | if event_data == node.event: 276 | return 277 | 278 | if node != _separator_node: 279 | var node_rect:Rect2 = node.get_rect() 280 | var node_event = node.get("event") 281 | 282 | _idx_hint = _edited_sequence.get_event_idx(node.event) 283 | if position.y > node_rect.size.y/2: 284 | _idx_hint = _edited_sequence.get_event_idx(node.event)+1 285 | 286 | if node.event.event_uses_subevents: 287 | subevent_of = node.event 288 | 289 | elif node.event.event_subevent_from: 290 | subevent_of = node.event.event_subevent_from.get_ref() 291 | 292 | if event_data.event_subevent_from: 293 | pass 294 | 295 | event_data.event_indent_level = node.event.event_indent_level 296 | 297 | if node is TimelineDisplayer: 298 | _idx_hint = -1 299 | event_data.event_indent_level = 0 300 | event_data.event_subevent_from = null 301 | 302 | if !is_moving_event: 303 | add_event(event_data, _idx_hint, _edited_sequence, subevent_of) 304 | else: 305 | move_event(event_data, _idx_hint, _edited_sequence, subevent_of) 306 | 307 | _idx_hint = -1 308 | 309 | 310 | func _generate_separator_node() -> void: 311 | _separator_node = EventNode.new() 312 | _separator_node.propagate_call("set", ["focus_mode", Control.FOCUS_NONE]) 313 | _separator_node.propagate_call("set", ["mouse_filter", Control.MOUSE_FILTER_PASS]) 314 | _separator_node.modulate.a = 0.5 315 | _separator_node.modulate = _separator_node.modulate.darkened(0.2) 316 | connect("tree_exited", _separator_node, "free") 317 | # _separator_node.set_drag_forwarding(self) 318 | timeline_displayer.add_child(_separator_node) 319 | 320 | 321 | func _get_undo_redo() -> UndoRedo: 322 | if not is_instance_valid(__undo_redo): 323 | __undo_redo = UndoRedo.new() 324 | connect("tree_exiting", __undo_redo, "free") 325 | return __undo_redo 326 | 327 | 328 | func _disconnect_edited_sequence_signals() -> void: 329 | if _edited_sequence: 330 | if _edited_sequence.is_connected("changed", self, "reload"): 331 | _edited_sequence.disconnect("changed",self,"reload") 332 | 333 | 334 | func _connect_edited_sequence_signals() -> void: 335 | if _edited_sequence: 336 | if not _edited_sequence.is_connected("changed",self,"reload"): 337 | _edited_sequence.connect("changed",self,"reload", [], CONNECT_DEFERRED) 338 | 339 | 340 | func _timeline_selected(_index:int) -> void: 341 | var current := _get_current() 342 | 343 | if current != "": 344 | var timeline = _edited_node.get_timeline(current) 345 | edit_timeline(timeline) 346 | 347 | 348 | func _timeline_tools_menu(option:int): 349 | match option: 350 | TOOL_NEW_TIMELINE: 351 | _timeline_new() 352 | 353 | TOOL_DUPLICATE_TIMELINE: 354 | _timeline_duplicate() 355 | 356 | TOOL_RENAME_TIMELINE: 357 | _timeline_rename() 358 | 359 | TOOL_REMOVE_TIMELINE: 360 | _timeline_remove() 361 | 362 | TOOL_EDIT_RESOURCE: 363 | _timeline_edit_resource() 364 | 365 | 366 | func _timeline_new() -> void: 367 | _renaming = false 368 | _name_dialog.window_title = "New Timeline" 369 | _new_name_edit.placeholder_text = "" 370 | _new_name_edit.text = "" 371 | _name_dialog.popup_centered() 372 | 373 | 374 | func _timeline_duplicate() -> void: 375 | var _timeline:TimelineClass = _edited_node.get_timeline(_get_current()) 376 | if _timeline == null: 377 | return 378 | 379 | # For some reason, duplicate(true) removes the script 380 | var new_timeline = _timeline.duplicate() 381 | 382 | var events = new_timeline.get_events() 383 | var new_events = [] 384 | for event in events: 385 | new_events.append(event.duplicate()) 386 | new_timeline.set_events(new_events) 387 | 388 | var new_name := _get_current() + " ({idx})" 389 | var idx = 2 390 | while _edited_node.has_timeline(new_name.format({"idx":idx})): 391 | idx += 1 392 | 393 | _edited_node.add_timeline(new_name.format({"idx":idx}), new_timeline) 394 | edit_node(_edited_node) 395 | 396 | func _timeline_rename() -> void: 397 | _renaming = true 398 | _name_dialog.window_title = "Rename Timeline" 399 | _new_name_edit.placeholder_text = _get_current() 400 | _new_name_edit.text = _get_current() 401 | _name_dialog.popup_centered() 402 | 403 | 404 | func _timeline_remove() -> void: 405 | _remove_label.text = "Removing '%s' timeline. Are you sure?"%_get_current() 406 | _remove_dialog.popup_centered() 407 | 408 | 409 | func _timeline_edit_resource() -> void: 410 | if !Engine.editor_hint: 411 | print("Tried to edit the resource, but you're not in the editor!") 412 | return 413 | emit_signal("inspection_requested", _edited_node.get_timeline(_get_current())) 414 | 415 | 416 | func _get_current() -> String: 417 | var current:String = "" 418 | var selected_id:int = _timeline_list.get_selected_id() 419 | 420 | if selected_id >= 0 && selected_id < _timeline_list.get_item_count(): 421 | current = _timeline_list.get_item_text(selected_id) 422 | 423 | return current 424 | 425 | 426 | func _input(event: InputEvent) -> void: 427 | var event_node = last_selected_event_node 428 | var focus_owner = get_focus_owner() 429 | 430 | if not is_instance_valid(event_node): 431 | return 432 | 433 | if is_instance_valid(focus_owner): 434 | if not event_node.is_a_parent_of(focus_owner): 435 | return 436 | 437 | var _event = last_selected_event_node.get("event") 438 | 439 | var duplicate_shortcut = shortcuts.get_shortcut("duplicate") 440 | if event.shortcut_match(duplicate_shortcut.shortcut): 441 | if _event and event.is_pressed(): 442 | timeline_displayer.remove_all_displayed_events() 443 | var position:int = _edited_sequence.get_events().find(_event) 444 | add_event(_event.duplicate(), position+1, event_node.timeline) 445 | event_node.accept_event() 446 | 447 | var delete_shortcut = shortcuts.get_shortcut("delete") 448 | if event.shortcut_match(delete_shortcut.shortcut): 449 | if _event: 450 | timeline_displayer.remove_all_displayed_events() 451 | remove_event(_event, event_node.timeline) 452 | event_node.accept_event() 453 | 454 | 455 | func _on_EventButton_selected(button) -> void: 456 | last_selected_event_node = button.get_meta("event_node") 457 | emit_signal("inspection_requested", last_selected_event_node.event) 458 | 459 | 460 | func _on_EventNode_gui_input(event: InputEvent, event_node:EventNode) -> void: 461 | var _event:EventClass = event_node.event 462 | 463 | if event is InputEventMouseButton: 464 | if event.button_index == BUTTON_RIGHT and event.pressed: 465 | if _event: 466 | _event_menu.used_event = _event 467 | _event_menu.popup(Rect2(get_global_mouse_position()+Vector2(1,1), _event_menu.rect_size)) 468 | event_node.event_button.pressed = true 469 | event_node.accept_event() 470 | 471 | 472 | func _on_TimelineDisplayer_event_node_added(event_node:Control) -> void: 473 | if not event_node.is_connected("gui_input", self, "_on_EventNode_gui_input"): 474 | event_node.connect("gui_input", self, "_on_EventNode_gui_input", [event_node]) 475 | 476 | event_node.set_drag_forwarding(self) 477 | event_node.set_button_group(__group) 478 | 479 | 480 | func _on_EventMenu_index_pressed(idx:int) -> void: 481 | var _used_event:EventClass = _event_menu.used_event as EventClass 482 | 483 | if _used_event == null: 484 | return 485 | 486 | # I'm not gonna lost my time recycling nodes tbh 487 | # timeline_displayer.remove_all_displayed_events() 488 | 489 | match idx: 490 | EventMenu.ItemType.EDIT: 491 | emit_signal("inspection_requested", _used_event) 492 | 493 | EventMenu.ItemType.DUPLICATE: 494 | var position:int = _edited_sequence.get_events().find(_used_event) 495 | add_event(_used_event.duplicate(), position+1) 496 | 497 | EventMenu.ItemType.REMOVE: 498 | remove_event(_used_event, _edited_sequence) 499 | 500 | 501 | func _on_CategoryManager_button_pressed(button:Button, event_script:Script) -> void: 502 | var idx := -1 503 | var timeline := _edited_sequence 504 | if is_instance_valid(last_selected_event_node): 505 | idx = last_selected_event_node.idx+1 506 | timeline = last_selected_event_node.timeline 507 | if not timeline: 508 | timeline = _edited_sequence 509 | idx = -1 510 | add_event(event_script.new(), idx, timeline) 511 | 512 | 513 | func _on_name_dialog_confirmed() -> void: 514 | if !is_instance_valid(_edited_node): 515 | return 516 | 517 | var new_name:String = _new_name_edit.text 518 | 519 | if new_name == "": 520 | _error_label.text = "Timeline label can't be empty" 521 | _error_dialog.popup_centered() 522 | return 523 | 524 | if new_name == "[None]": 525 | _error_label.text = "Invalid name!" 526 | _error_dialog.popup_centered() 527 | return 528 | 529 | if _renaming: 530 | _renaming = false 531 | 532 | if new_name == _get_current(): 533 | _name_dialog.hide() 534 | return 535 | 536 | _edited_node.rename_timeline(_get_current(), new_name) 537 | 538 | else: 539 | if _edited_node.has_timeline(new_name): 540 | _error_label.text = "Timeline '%s' already exist"%new_name 541 | _error_dialog.popup_centered() 542 | return 543 | 544 | var res:TimelineClass = TimelineClass.new() 545 | res.resource_name = new_name 546 | _edited_node.add_timeline(new_name, res) 547 | 548 | edit_node(_edited_node) 549 | edit_timeline_by_name(new_name) 550 | 551 | if _get_undo_redo() != null: 552 | _get_undo_redo().clear_history() 553 | 554 | _name_dialog.hide() 555 | 556 | 557 | func _on_remove_dialog_confirmed() -> void: 558 | if !is_instance_valid(_edited_node): 559 | return 560 | 561 | _edited_node.remove_timeline(_get_current()) 562 | edit_node(_edited_node) 563 | 564 | func _init() -> void: 565 | __group = ButtonGroup.new() 566 | __group.connect("pressed", self, "_on_EventButton_selected") 567 | add_constant_override("separation", 2) 568 | theme = load("res://addons/event_system_plugin/assets/themes/timeline_editor.tres") as Theme 569 | mouse_filter = Control.MOUSE_FILTER_STOP 570 | 571 | _sc = ScrollContainer.new() 572 | _sc.follow_focus = true 573 | _sc.size_flags_horizontal = SIZE_EXPAND_FILL 574 | _sc.size_flags_vertical = SIZE_EXPAND_FILL 575 | _sc.mouse_filter = Control.MOUSE_FILTER_PASS 576 | var scale := 1.0 577 | 578 | if Engine.editor_hint: 579 | var plugin:EditorPlugin = EditorPlugin.new() 580 | scale = float(plugin.get_editor_interface().get_editor_scale()) 581 | plugin.free() 582 | 583 | _sc.rect_min_size = Vector2(0, 180) * scale 584 | 585 | var _dummy_panel := PanelContainer.new() 586 | _dummy_panel.size_flags_horizontal = SIZE_EXPAND_FILL 587 | _dummy_panel.size_flags_vertical = SIZE_EXPAND_FILL 588 | _dummy_panel.mouse_filter = Control.MOUSE_FILTER_STOP 589 | _dummy_panel.focus_mode = Control.FOCUS_CLICK 590 | _sc.add_child(_dummy_panel) 591 | 592 | var timeline_drawer = load("res://addons/event_system_plugin/nodes/editor/timeline_drawer.gd").new() 593 | timeline_drawer.focus_mode = Control.FOCUS_NONE 594 | timeline_drawer.mouse_filter = Control.MOUSE_FILTER_IGNORE 595 | _dummy_panel.add_child(timeline_drawer) 596 | 597 | timeline_displayer = TimelineDisplayer.new() 598 | timeline_displayer.connect("event_node_added", self, "_on_TimelineDisplayer_event_node_added") 599 | _dummy_panel.add_child(timeline_displayer) 600 | timeline_drawer.timeline_displayer = timeline_displayer 601 | timeline_displayer.set_drag_forwarding(self) 602 | 603 | _category_manager = CategoryManager.new() 604 | _category_manager.connect("toolbar_button_pressed", self, "_on_CategoryManager_button_pressed") 605 | 606 | _event_menu = EventMenu.new() 607 | _event_menu.connect("index_pressed", self, "_on_EventMenu_index_pressed") 608 | _event_menu.connect("hide", _event_menu, "set", ["used_event", null]) 609 | 610 | var _hs := HSplitContainer.new() 611 | _hs.size_flags_horizontal = SIZE_EXPAND_FILL 612 | _hs.size_flags_vertical = SIZE_EXPAND_FILL 613 | 614 | _hs.add_child(_category_manager) 615 | 616 | var _vb = VBoxContainer.new() 617 | _vb.add_constant_override("separation", 4) 618 | 619 | var _toolbar := HBoxContainer.new() 620 | _timeline_tools = MenuButton.new() 621 | _timeline_tools.text = "Timeline" 622 | _timeline_tools.flat = false 623 | 624 | _timeline_tools.get_popup().add_item("New", TOOL_NEW_TIMELINE) 625 | _timeline_tools.get_popup().add_separator() 626 | _timeline_tools.get_popup().add_item("Duplicate", TOOL_DUPLICATE_TIMELINE) 627 | _timeline_tools.get_popup().add_separator() 628 | _timeline_tools.get_popup().add_item("Rename...", TOOL_RENAME_TIMELINE) 629 | _timeline_tools.get_popup().add_item("Open in Inspector", TOOL_EDIT_RESOURCE) 630 | _timeline_tools.get_popup().add_separator() 631 | _timeline_tools.get_popup().add_item("Remove", TOOL_REMOVE_TIMELINE) 632 | 633 | _timeline_list = TimelineList.new() 634 | _timeline_list.size_flags_horizontal = SIZE_EXPAND_FILL 635 | 636 | _name_dialog = ConfirmationDialog.new() 637 | _name_dialog.window_title = "Create New Timeline" 638 | _name_dialog.dialog_hide_on_ok = false 639 | add_child(_name_dialog) 640 | 641 | var vb = VBoxContainer.new() 642 | _name_dialog.add_child(vb) 643 | 644 | _new_name_label = Label.new() 645 | _new_name_label.text = "Timeline name:" 646 | vb.add_child(_new_name_label) 647 | 648 | _new_name_edit = LineEdit.new() 649 | _new_name_edit.size_flags_horizontal = SIZE_EXPAND_FILL 650 | vb.add_child(_new_name_edit) 651 | _name_dialog.register_text_enter(_new_name_edit) 652 | 653 | _error_dialog = AcceptDialog.new() 654 | _error_dialog.window_title = "Error!" 655 | add_child(_error_dialog) 656 | 657 | _error_label = Label.new() 658 | _error_dialog.add_child(_error_label) 659 | 660 | _remove_dialog = ConfirmationDialog.new() 661 | add_child(_remove_dialog) 662 | 663 | _remove_label = Label.new() 664 | _remove_label.text = "Are you sure?" 665 | _remove_dialog.add_child(_remove_label) 666 | 667 | _info_label = Label.new() 668 | _info_label.align = Label.ALIGN_CENTER 669 | _info_label.visible = false 670 | 671 | _toolbar.add_child(_timeline_tools) 672 | _toolbar.add_child(_timeline_list) 673 | _vb.add_child(_info_label) 674 | _vb.add_child(_toolbar) 675 | _vb.add_child(_sc) 676 | 677 | _hs.add_child(_vb) 678 | 679 | add_child(_hs) 680 | add_child(_event_menu) 681 | 682 | 683 | func _notification(what: int) -> void: 684 | match what: 685 | NOTIFICATION_ENTER_TREE: 686 | _timeline_list.connect("item_selected", self, "_timeline_selected") 687 | _timeline_tools.get_popup().connect("id_pressed", self, "_timeline_tools_menu") 688 | _name_dialog.connect("confirmed", self, "_on_name_dialog_confirmed") 689 | _remove_dialog.connect("confirmed", self, "_on_remove_dialog_confirmed") 690 | 691 | NOTIFICATION_DRAG_END: 692 | if is_instance_valid(_separator_node): 693 | _separator_node.queue_free() 694 | 695 | if is_moving_event: 696 | is_moving_event = false 697 | 698 | NOTIFICATION_THEME_CHANGED: 699 | # For some reason this is called _before_ init (what?!) 700 | if !is_inside_tree(): 701 | return 702 | _sc.add_stylebox_override("bg",get_stylebox("bg", "Tree")) 703 | _timeline_tools.add_stylebox_override("normal", get_stylebox("normal", "Button")) 704 | 705 | var menu:PopupMenu = _timeline_tools.get_popup() 706 | menu.set_item_icon(menu.get_item_index(TOOL_NEW_TIMELINE), get_icon("New", "EditorIcons")) 707 | menu.set_item_icon(menu.get_item_index(TOOL_DUPLICATE_TIMELINE), get_icon("Duplicate", "EditorIcons")) 708 | menu.set_item_icon(menu.get_item_index(TOOL_EDIT_RESOURCE), get_icon("Edit", "EditorIcons")) 709 | menu.set_item_icon(menu.get_item_index(TOOL_REMOVE_TIMELINE), get_icon("Remove", "EditorIcons")) 710 | menu.set_item_icon(menu.get_item_index(TOOL_RENAME_TIMELINE), get_icon("Rename", "EditorIcons")) 711 | 712 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/timeline_list.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends OptionButton 3 | 4 | const EvManager = preload("res://addons/event_system_plugin/nodes/event_manager/event_manager.gd") 5 | 6 | var plugin:EditorPlugin 7 | var node:EvManager 8 | 9 | func list_timelines() -> void: 10 | clear() 11 | if !is_instance_valid(node): 12 | disabled = true 13 | return 14 | 15 | disabled = false 16 | for timeline_name in node.get_timeline_list(): 17 | add_item(timeline_name) 18 | 19 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/welcome/main_panel.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Control 3 | 4 | export(NodePath) var VersionNodePath:NodePath 5 | 6 | var repository:String = "" 7 | var docs:String = "" 8 | var version:String = "0" 9 | 10 | onready var version_node:Label = get_node(VersionNodePath) as Label 11 | 12 | func _ready() -> void: 13 | version_node.text = version 14 | 15 | 16 | func _on_Docs_pressed() -> void: 17 | OS.shell_open(docs) 18 | 19 | 20 | func _on_Repository_pressed() -> void: 21 | OS.shell_open(repository) 22 | 23 | 24 | func _on_License_pressed() -> void: 25 | var license_path = ProjectSettings.globalize_path("res://addons/event_system_plugin/LICENSE") 26 | OS.shell_open(license_path) 27 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/editor/welcome/main_panel.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=2] 2 | 3 | [ext_resource path="res://icon.png" type="Texture" id=1] 4 | [ext_resource path="res://addons/event_system_plugin/nodes/editor/welcome/main_panel.gd" type="Script" id=2] 5 | 6 | [node name="PanelContainer" type="PanelContainer"] 7 | anchor_right = 1.0 8 | anchor_bottom = 1.0 9 | size_flags_horizontal = 3 10 | size_flags_vertical = 3 11 | script = ExtResource( 2 ) 12 | __meta__ = { 13 | "_edit_use_anchors_": false 14 | } 15 | VersionNodePath = NodePath("VBoxContainer/HBoxContainer/VBoxContainer/Version") 16 | 17 | [node name="VBoxContainer" type="VBoxContainer" parent="."] 18 | margin_left = 32.0 19 | margin_top = 7.0 20 | margin_right = 1017.0 21 | margin_bottom = 593.0 22 | 23 | [node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] 24 | margin_right = 985.0 25 | margin_bottom = 562.0 26 | size_flags_vertical = 3 27 | custom_constants/separation = 16 28 | 29 | [node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/HBoxContainer"] 30 | margin_right = 128.0 31 | margin_bottom = 562.0 32 | alignment = 1 33 | 34 | [node name="Button" type="Button" parent="VBoxContainer/HBoxContainer/VBoxContainer"] 35 | margin_top = 208.0 36 | margin_right = 128.0 37 | margin_bottom = 336.0 38 | rect_min_size = Vector2( 128, 128 ) 39 | icon = ExtResource( 1 ) 40 | clip_text = true 41 | expand_icon = true 42 | 43 | [node name="Version" type="Label" parent="VBoxContainer/HBoxContainer/VBoxContainer"] 44 | margin_top = 340.0 45 | margin_right = 128.0 46 | margin_bottom = 354.0 47 | text = "{VERSION_NUMBER}" 48 | align = 1 49 | 50 | [node name="VBoxContainer2" type="VBoxContainer" parent="VBoxContainer/HBoxContainer"] 51 | margin_left = 144.0 52 | margin_right = 985.0 53 | margin_bottom = 562.0 54 | size_flags_horizontal = 3 55 | alignment = 1 56 | 57 | [node name="Label3" type="Label" parent="VBoxContainer/HBoxContainer/VBoxContainer2"] 58 | margin_top = 207.0 59 | margin_right = 841.0 60 | margin_bottom = 255.0 61 | text = "Many thanks for using EventSystem! 62 | 63 | This plugin was made for the comunnity." 64 | autowrap = true 65 | 66 | [node name="HSeparator2" type="HSeparator" parent="VBoxContainer/HBoxContainer/VBoxContainer2"] 67 | margin_top = 259.0 68 | margin_right = 841.0 69 | margin_bottom = 263.0 70 | __meta__ = { 71 | "_edit_use_anchors_": false 72 | } 73 | 74 | [node name="Label" type="Label" parent="VBoxContainer/HBoxContainer/VBoxContainer2"] 75 | margin_top = 267.0 76 | margin_right = 841.0 77 | margin_bottom = 281.0 78 | text = "Take a look in the documentation page:" 79 | 80 | [node name="Docs" type="Button" parent="VBoxContainer/HBoxContainer/VBoxContainer2"] 81 | margin_top = 285.0 82 | margin_right = 841.0 83 | margin_bottom = 305.0 84 | text = "Documentation Page" 85 | 86 | [node name="HSeparator" type="HSeparator" parent="VBoxContainer/HBoxContainer/VBoxContainer2"] 87 | margin_top = 309.0 88 | margin_right = 841.0 89 | margin_bottom = 313.0 90 | 91 | [node name="Label2" type="Label" parent="VBoxContainer/HBoxContainer/VBoxContainer2"] 92 | margin_top = 317.0 93 | margin_right = 841.0 94 | margin_bottom = 331.0 95 | text = "Github Repository:" 96 | 97 | [node name="Repository" type="Button" parent="VBoxContainer/HBoxContainer/VBoxContainer2"] 98 | margin_top = 335.0 99 | margin_right = 841.0 100 | margin_bottom = 355.0 101 | hint_tooltip = "You can report bugs, request features or help with the plugin here" 102 | text = "AnidemDex/Godot-EventSystem" 103 | 104 | [node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer"] 105 | margin_top = 566.0 106 | margin_right = 985.0 107 | margin_bottom = 586.0 108 | 109 | [node name="License" type="Button" parent="VBoxContainer/HBoxContainer2"] 110 | margin_right = 91.0 111 | margin_bottom = 20.0 112 | text = "MIT LICENSE" 113 | 114 | [connection signal="pressed" from="VBoxContainer/HBoxContainer/VBoxContainer2/Docs" to="." method="_on_Docs_pressed"] 115 | [connection signal="pressed" from="VBoxContainer/HBoxContainer/VBoxContainer2/Repository" to="." method="_on_Repository_pressed"] 116 | [connection signal="pressed" from="VBoxContainer/HBoxContainer2/License" to="." method="_on_License_pressed"] 117 | -------------------------------------------------------------------------------- /addons/event_system_plugin/nodes/event_manager/event_manager.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Node 3 | class_name EventManager 4 | 5 | ## 6 | ## Base class for all event manager nodes. 7 | ## 8 | ## EventManager executes the event behaviour, and manages the event order execution. 9 | ## 10 | 11 | signal custom_signal(data) 12 | 13 | ## Emmited when an Event is executed. Event resource is passed in the signal 14 | signal event_started(event) 15 | ## Emmited when an Event finished. Event resource is passed in the signal. 16 | signal event_finished(event) 17 | 18 | ## Emmited when a timeline starts. Timeline resource is passed in the signal 19 | signal timeline_started(timeline_resource) 20 | ## Emmited when a timeline finish. Timeline resource is passed in the signal 21 | signal timeline_finished(timeline_resource) 22 | 23 | ## This is the node were events will be applied to. 24 | ## This node is used if the event doesn't define an [member Event.event_node_path] 25 | ## and is relative to the current scene node owner. 26 | export(NodePath) var event_node_fallback_path:NodePath = "." 27 | ## If is [code]true[/code], the node will call [method start_timeline] when owner is ready. 28 | export(bool) var start_on_ready:bool = false 29 | 30 | ## Current timeline name. You can get the current timeline resource with [method get_timeline] 31 | var current_timeline:String="" 32 | ## Current executed event. 33 | var current_event 34 | ## The current event position accordint to [member current_timeline] resource. 35 | var current_idx:int = -1 36 | 37 | var __data := {} 38 | 39 | func _ready() -> void: 40 | if Engine.editor_hint: 41 | return 42 | 43 | if start_on_ready: 44 | call_deferred("start_timeline", current_timeline) 45 | 46 | ## Starts timeline. This method must be called to start EventManager process. 47 | ## [code]timeline_name[/code] is the name of any timeline saved in the node. 48 | ## You can optionally pass [code]from_event_index[/code] to define from 49 | ## where the timeline should start. 50 | func start_timeline(timeline_name:String, from_event_index:int=0) -> void: 51 | if timeline_name == "[None]": 52 | return 53 | 54 | if !has_timeline(timeline_name): 55 | push_error("start_timeline: Can't find %p timeline"%timeline_name) 56 | return 57 | 58 | current_timeline = timeline_name 59 | _notify_timeline_start() 60 | go_to_next_event() 61 | 62 | ## Advances to the next event in the current timeline. 63 | func go_to_next_event() -> void: 64 | var event 65 | 66 | if current_timeline == "" or !has_timeline(current_timeline): 67 | # For some reason, the current timeline doesn't exist 68 | 69 | return 70 | 71 | 72 | if current_event: 73 | if "next_event" in current_event and current_event["next_event"] != "": 74 | var data = current_event.get("next_event").split(";") 75 | current_idx = int(data[0]) 76 | var new_timeline = "" 77 | if data.size() > 1: 78 | new_timeline = data[1] 79 | 80 | if new_timeline != "": 81 | current_timeline = new_timeline 82 | else: 83 | current_idx += 1 84 | 85 | if current_idx < 0: 86 | current_idx = 0 87 | 88 | var timeline = get_timeline(current_timeline) 89 | 90 | event = timeline.get("event/{idx}".format({"idx":current_idx})) 91 | current_event = event 92 | 93 | if current_event == null: 94 | _notify_timeline_end() 95 | return 96 | 97 | _execute_event(event) 98 | 99 | ## Adds a [code]timeline[/code] to this node named [code]timeline_name[/code]. 100 | func add_timeline(timeline_name:String, timeline) -> void: 101 | if timeline_name == "": 102 | push_error("add_timeline: Tried to add a timeline with an empty name!") 103 | return 104 | 105 | if timeline == null: 106 | push_error("add_timeline: Tried to add '%s' with a null value"%timeline_name) 107 | return 108 | 109 | if has_timeline(timeline_name): 110 | push_error("add_timeline: Timeline '%s' already exist"%timeline_name) 111 | return 112 | 113 | __data[timeline_name] = timeline 114 | property_list_changed_notify() 115 | 116 | ## Returns the [code]timeline[/code] associated to [code]timeline_name[/code] 117 | func get_timeline(timeline_name:String) -> Timeline: 118 | var res = null 119 | 120 | if !has_timeline(timeline_name): 121 | push_error("get_timeline: Can't find {n} timeline".format({"n":timeline_name})) 122 | 123 | res = __data.get(timeline_name, null) 124 | return res 125 | 126 | ## Returns true if the node has a [code]timeline_name[/code] 127 | func has_timeline(timeline_name:String) -> bool: 128 | return __data.has(timeline_name) 129 | 130 | ## Removes the timeline associated to [code]timeline_name[/code] 131 | func remove_timeline(timeline_name:String) -> void: 132 | if !has_timeline(timeline_name): 133 | push_warning("remove_timeline: Tried to remove '%s' timeline but the timeline doesn't exist."%timeline_name) 134 | return 135 | __data.erase(timeline_name) 136 | property_list_changed_notify() 137 | 138 | ## Renames [code]timeline_name[/code] to [code]new_name[/code] 139 | func rename_timeline(timeline_name:String, new_name:String) -> void: 140 | var timeline:Timeline = get_timeline(timeline_name) 141 | 142 | if !has_timeline(timeline_name): 143 | push_warning("rename_timeline: Tried to rename '%s' timeline but the timeline doesn't exist."%timeline_name) 144 | return 145 | 146 | if has_timeline(new_name): 147 | push_warning("rename_timeline: Tried to rename '{name}' timeline to '{new_name}' but '{new_name}' already exist.".format({"name":timeline_name, "new_name":new_name})) 148 | return 149 | 150 | remove_timeline(timeline_name) 151 | add_timeline(new_name, timeline) 152 | 153 | ## Returns a [class PoolStringArray] containing timeline names saved on this node. 154 | func get_timeline_list() -> PoolStringArray: 155 | return PoolStringArray(__data.keys()) 156 | 157 | 158 | func _execute_event(event:Event) -> void: 159 | if event == null: 160 | assert(false) 161 | return 162 | 163 | var node:Node = self if event_node_fallback_path == @"." else get_node(event_node_fallback_path) 164 | # This is a crime, needs to be modified in future versions 165 | event.set("_event_manager", self) 166 | event.set("_event_node_fallback", node) 167 | 168 | _connect_event_signals(event) 169 | 170 | event.execute() 171 | 172 | 173 | func _connect_event_signals(event:Event) -> void: 174 | if not event.is_connected("event_started", self, "_on_Event_started"): 175 | event.connect("event_started", self, "_on_Event_started", [], CONNECT_ONESHOT) 176 | if not event.is_connected("event_finished", self, "_on_Event_finished"): 177 | event.connect("event_finished", self, "_on_Event_finished", [], CONNECT_ONESHOT) 178 | 179 | 180 | func _on_Event_started(event:Event) -> void: 181 | emit_signal("event_started", event) 182 | 183 | 184 | func _on_Event_finished(event:Event) -> void: 185 | emit_signal("event_finished", event) 186 | if event.continue_at_end: 187 | go_to_next_event() 188 | 189 | 190 | func _notify_timeline_start() -> void: 191 | emit_signal("timeline_started", get_timeline(current_timeline)) 192 | 193 | 194 | func _notify_timeline_end() -> void: 195 | emit_signal("timeline_finished", get_timeline(current_timeline)) 196 | 197 | 198 | func _hide_script_from_inspector(): 199 | return true 200 | 201 | 202 | func _set(property:String, value) -> bool: 203 | if property == "timeline": 204 | property = "timeline/legacy_timeline" 205 | 206 | if property.begins_with("timeline/"): 207 | var p := property.replace("timeline/", "") 208 | if p == "": 209 | return false 210 | 211 | add_timeline(p, value) 212 | property_list_changed_notify() 213 | 214 | return true 215 | 216 | return false 217 | 218 | 219 | func _get(property: String): 220 | if property.begins_with("timeline/"): 221 | var p := property.replace("timeline/", "") 222 | if p == "": 223 | return 224 | 225 | return get_timeline(p) 226 | 227 | 228 | func property_can_revert(property:String) -> bool: 229 | if property == "current_timeline": 230 | return true 231 | return false 232 | 233 | 234 | func property_get_revert(property:String): 235 | if property == "current_timeline": 236 | return "[None]" 237 | 238 | 239 | func _get_property_list() -> Array: 240 | var p := [] 241 | var hint_string = "[None]" 242 | for timeline_name in get_timeline_list(): 243 | hint_string += ",%s"%timeline_name 244 | p.append({"type":TYPE_STRING, "name":"current_timeline", "hint":PROPERTY_HINT_ENUM, "hint_string":hint_string, "usage":PROPERTY_USAGE_SCRIPT_VARIABLE|PROPERTY_USAGE_DEFAULT}) 245 | 246 | var usage := PROPERTY_USAGE_SCRIPT_VARIABLE | PROPERTY_USAGE_NOEDITOR 247 | for timeline_name in __data.keys(): 248 | p.append({"type":TYPE_OBJECT, "name":"timeline/"+timeline_name, "usage":usage}) 249 | return p 250 | -------------------------------------------------------------------------------- /addons/event_system_plugin/plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="EventSystem" 4 | description="An easy but powerful event system implementation for Godot Engine" 5 | author="AnidemDex" 6 | version="2.0" 7 | script="plugin_script.gd" 8 | repository="https://github.com/AnidemDex/Godot-EventSystem" 9 | license="https://github.com/AnidemDex/Godot-EventSystem/blob/main/LICENSE" 10 | docs="https://godotplugins.gitbook.io/eventsystem/" 11 | -------------------------------------------------------------------------------- /addons/event_system_plugin/plugin_script.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends "godot_plugin.gd" 3 | 4 | const TimelineEditor = preload("nodes/editor/timeline_editor.gd") 5 | const EventManagerClass = preload("nodes/event_manager/event_manager.gd") 6 | const EventClass = preload("resources/event_class/event_class.gd") 7 | const TimelineClass = preload("resources/timeline_class/timeline_class.gd") 8 | 9 | var timeline_editor:TimelineEditor 10 | var timeline_dock_button:ToolButton 11 | 12 | func _enter_tree(): 13 | var inspector:EditorInspectorPlugin = load("res://addons/event_system_plugin/core/event_inspector.gd").new() 14 | register_editor_plugin(inspector) 15 | 16 | show_plugin_version_button() 17 | 18 | timeline_editor.connect("inspection_requested", self, "_on_TimelineEditor_inspect") 19 | timeline_dock_button = add_control_to_bottom_panel(timeline_editor, "TimelineEditor") 20 | timeline_dock_button.call_deferred("hide") 21 | 22 | var main_panel:PanelContainer = load("res://addons/event_system_plugin/nodes/editor/welcome/main_panel.tscn").instance() 23 | main_panel.set("repository", get_plugin_repository()) 24 | main_panel.set("docs", get_plugin_docs_url()) 25 | main_panel.set("version", get_plugin_version()) 26 | get_plugin_welcome_node().get_tab_by_idx(0).add_child(main_panel) 27 | 28 | 29 | func _enable_plugin(): 30 | show_welcome_node() 31 | 32 | 33 | func _handles(object: Object) -> bool: 34 | if object is Script: 35 | return false 36 | 37 | if object.get_class() == "ScriptEditorDebuggerInspectedObject": 38 | return false 39 | 40 | 41 | if object as EventManagerClass != null: 42 | return true 43 | 44 | if object as TimelineClass != null: 45 | return true 46 | 47 | return false 48 | 49 | 50 | func _edit(object: Object) -> void: 51 | timeline_editor.set_undo_redo(get_undo_redo()) 52 | timeline_editor.edit(object) 53 | 54 | 55 | func _make_visible(visible: bool) -> void: 56 | if visible: 57 | timeline_dock_button.show() 58 | make_bottom_panel_item_visible(timeline_editor) 59 | timeline_editor.set_process_input(true) 60 | else: 61 | if timeline_dock_button.is_visible_in_tree(): 62 | hide_bottom_panel() 63 | timeline_dock_button.hide() 64 | timeline_editor.set_process_input(false) 65 | 66 | 67 | func _scene_change(scene_root:Node) -> void: 68 | pass 69 | 70 | 71 | func _on_TimelineEditor_inspect(resource:Resource) -> void: 72 | get_editor_interface().inspect_object(resource, "", true) 73 | 74 | 75 | func _init() -> void: 76 | timeline_editor = TimelineEditor.new() 77 | register_plugin_node(timeline_editor) 78 | 79 | connect("scene_changed", self, "_scene_change") 80 | -------------------------------------------------------------------------------- /addons/event_system_plugin/resources/event_class/event_class.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Resource 3 | class_name Event, "res://addons/event_system_plugin/assets/icons/timeline_icon.png" 4 | 5 | ## 6 | ## Base class for all events. 7 | ## 8 | ## Every event relies on this class. 9 | ## If you want to do your own event, you should [code]extend[/code] this class. 10 | ## 11 | 12 | ## Emmited when the event starts. 13 | ## The signal is emmited with the event resource [code]event_resource[/code] 14 | signal event_started(event_resource) 15 | 16 | ## Emmited when the event finish. 17 | ## The signal is emmited with the event resource [code]event_resource[/code] 18 | signal event_finished(event_resource) 19 | 20 | ########## 21 | # Default Event Properties 22 | ########## 23 | 24 | ## Determines if the event will go to next event inmediatly or not. 25 | ## If value is true, the next event will be executed when event ends. 26 | export(bool) var continue_at_end:bool = true setget _set_continue 27 | 28 | var event_node_path:NodePath setget _set_event_node_path 29 | 30 | ########## 31 | # Event Editor Properties 32 | ########## 33 | 34 | ## The event icon that'll be displayed in the editor 35 | var event_icon:Texture setget ,get_event_icon 36 | 37 | ## The event color that event node will take in the editor 38 | var event_color:Color = Color("FBB13C") 39 | 40 | ## The event name that'll be displayed in the editor. 41 | ## If the resource name is different from the event name, resource_name is returned instead. 42 | var event_name:String = "Event" setget ,get_event_name 43 | 44 | ## The event preview string that will be displayed next to the event name in the editor. 45 | ## You can use String formats to parse variables from the script: 46 | ## [codeblock] event_preview_string = "{resource_name}" [/codeblock] 47 | ## Will display the resource's name instead of [code]{resource_name}[/code]. 48 | var event_preview_string:String = "" 49 | 50 | ## The event hint that'll be displayed when you hover the event button in the editor. 51 | var event_hint:String = "" 52 | 53 | ## The event category it belongs to. Used by the editor. 54 | var event_category:String = "Custom" 55 | 56 | ## The event indentation level. Used by the editor. 57 | var event_indent_level:int = 0 58 | 59 | ## Determines if this event uses subevents. 60 | var event_uses_subevents:bool = false 61 | 62 | ## The quantity of subevents this event has. 63 | var event_subevents_quantity:int = 0 64 | 65 | ## Assigned by the editor. 66 | var event_subevent_from:WeakRef = null 67 | 68 | var _event_manager:Node 69 | var _event_node_fallback:Node 70 | 71 | ## Executes the event behaviour. 72 | func execute() -> void: 73 | emit_signal("event_started", self) 74 | 75 | call_deferred("_execute") 76 | 77 | 78 | ## Ends the event behaviour. 79 | func finish() -> void: 80 | emit_signal("event_finished", self) 81 | 82 | 83 | func _execute() -> void: 84 | finish() 85 | 86 | 87 | func get_event_name() -> String: 88 | if event_name != resource_name and resource_name != "": 89 | return resource_name 90 | return event_name 91 | 92 | 93 | func get_event_manager_node() -> Node: 94 | return _event_manager 95 | 96 | 97 | func get_event_node() -> Node: 98 | var event_node:Node 99 | if event_node_path != NodePath(): 100 | event_node = get_event_manager_node().get_tree().current_scene.get_node(event_node_path) 101 | 102 | if not is_instance_valid(event_node): 103 | event_node = _event_node_fallback 104 | 105 | return event_node 106 | 107 | 108 | func get_event_icon() -> Texture: 109 | if event_icon: 110 | return event_icon 111 | 112 | var theme:Theme = load("res://addons/event_system_plugin/assets/themes/timeline_editor.tres") 113 | var good_name = event_name.replace(" ","_").to_lower() 114 | if theme.has_icon(good_name, "EventIcons"): 115 | return theme.get_icon(good_name, "EventIcons") as Texture 116 | 117 | return theme.get_icon("custom", "EventIcons") as Texture 118 | 119 | 120 | func _set_continue(value:bool) -> void: 121 | continue_at_end = value 122 | property_list_changed_notify() 123 | emit_changed() 124 | 125 | 126 | func _set_event_node_path(value:NodePath) -> void: 127 | event_node_path = value 128 | property_list_changed_notify() 129 | emit_changed() 130 | 131 | 132 | func _set(property: String, value) -> bool: 133 | 134 | if property == "event_manager": 135 | _event_manager = value 136 | return true 137 | 138 | if property == "resource_name": 139 | event_name = property 140 | emit_changed() 141 | property_list_changed_notify() 142 | return true 143 | 144 | return false 145 | 146 | func _get(property: String): 147 | if property == "resource_name": 148 | return event_name 149 | 150 | 151 | func _get_property_list() -> Array: 152 | var p:Array = [] 153 | p.append({"name":"event_node_path", "type":TYPE_NODE_PATH}) 154 | p.append({"name":"event_subevents_quantity", "type":TYPE_INT, "usage":PROPERTY_USAGE_SCRIPT_VARIABLE|PROPERTY_USAGE_NOEDITOR}) 155 | 156 | return p 157 | 158 | 159 | func property_can_revert(property:String) -> bool: 160 | if property == "event_node_path": 161 | return true 162 | return false 163 | 164 | 165 | func property_get_revert(property:String): 166 | if property == "event_node_path": 167 | return NodePath() 168 | 169 | 170 | func _to_string() -> String: 171 | return "[{event_name}:{id}]".format({"event_name":event_name, "id":get_instance_id()}) 172 | 173 | 174 | func _hide_script_from_inspector(): 175 | return true 176 | -------------------------------------------------------------------------------- /addons/event_system_plugin/resources/registered_events/_.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends "res://addons/event_system_plugin/resources/timeline_class/timeline_class.gd" 3 | 4 | ## This file stores events displayed in the editor toolbar. 5 | 6 | func _init(): 7 | var events = [ 8 | load("res://addons/event_system_plugin/events/call_from.gd").new(), 9 | load("res://addons/event_system_plugin/events/comment.gd").new(), 10 | load("res://addons/event_system_plugin/events/emit_signal.gd").new(), 11 | load("res://addons/event_system_plugin/events/end_timeline.gd").new(), 12 | load("res://addons/event_system_plugin/events/hide.gd").new(), 13 | load("res://addons/event_system_plugin/events/condition.gd").new(), 14 | load("res://addons/event_system_plugin/events/set.gd").new(), 15 | load("res://addons/event_system_plugin/events/show.gd").new(), 16 | load("res://addons/event_system_plugin/events/wait.gd").new(), 17 | load("res://addons/event_system_plugin/events/goto.gd").new() 18 | ] 19 | 20 | for ev in events: 21 | register_event(ev) 22 | 23 | 24 | func register_event(event) -> void: 25 | if event == null: 26 | return 27 | 28 | var _scripts := [] 29 | for _event in _events: 30 | _scripts.append((event as Resource).get_script()) 31 | 32 | if event.get_script() in _scripts: 33 | return 34 | 35 | add_event(event) 36 | -------------------------------------------------------------------------------- /addons/event_system_plugin/resources/registered_events/registered_events.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=22 format=2] 2 | 3 | [ext_resource path="res://addons/event_system_plugin/resources/registered_events/_.gd" type="Script" id=1] 4 | [ext_resource path="res://addons/event_system_plugin/events/comment.gd" type="Script" id=2] 5 | [ext_resource path="res://addons/event_system_plugin/events/set.gd" type="Script" id=3] 6 | [ext_resource path="res://addons/event_system_plugin/events/goto.gd" type="Script" id=4] 7 | [ext_resource path="res://addons/event_system_plugin/events/wait.gd" type="Script" id=5] 8 | [ext_resource path="res://addons/event_system_plugin/events/condition.gd" type="Script" id=6] 9 | [ext_resource path="res://addons/event_system_plugin/events/emit_signal.gd" type="Script" id=7] 10 | [ext_resource path="res://addons/event_system_plugin/events/show.gd" type="Script" id=9] 11 | [ext_resource path="res://addons/event_system_plugin/events/hide.gd" type="Script" id=10] 12 | [ext_resource path="res://addons/event_system_plugin/events/end_timeline.gd" type="Script" id=11] 13 | [ext_resource path="res://addons/event_system_plugin/events/call_from.gd" type="Script" id=12] 14 | 15 | [sub_resource type="Resource" id=1] 16 | resource_name = "Call" 17 | script = ExtResource( 12 ) 18 | continue_at_end = true 19 | method = "" 20 | args = [ ] 21 | event_node_path = NodePath("") 22 | event_subevents_quantity = 0 23 | 24 | [sub_resource type="Resource" id=2] 25 | resource_name = "Comment" 26 | script = ExtResource( 2 ) 27 | continue_at_end = true 28 | text = "" 29 | event_node_path = NodePath("") 30 | event_subevents_quantity = 0 31 | 32 | [sub_resource type="Resource" id=3] 33 | resource_name = "Emit Signal" 34 | script = ExtResource( 7 ) 35 | continue_at_end = true 36 | data = "" 37 | event_node_path = NodePath("") 38 | event_subevents_quantity = 0 39 | 40 | [sub_resource type="Resource" id=4] 41 | resource_name = "End Timeline" 42 | script = ExtResource( 11 ) 43 | continue_at_end = true 44 | event_node_path = NodePath("") 45 | event_subevents_quantity = 0 46 | 47 | [sub_resource type="Resource" id=5] 48 | resource_name = "Hide" 49 | script = ExtResource( 10 ) 50 | continue_at_end = true 51 | method = "set" 52 | args = [ "visible", false ] 53 | event_node_path = NodePath("") 54 | event_subevents_quantity = 0 55 | 56 | [sub_resource type="Resource" id=6] 57 | resource_name = "Condition" 58 | script = ExtResource( 6 ) 59 | continue_at_end = true 60 | condition = "" 61 | event_node_path = NodePath("") 62 | event_subevents_quantity = 0 63 | 64 | [sub_resource type="Resource" id=7] 65 | resource_name = "Set" 66 | script = ExtResource( 3 ) 67 | continue_at_end = true 68 | method = "set" 69 | args = [ "", "" ] 70 | variable_name = "" 71 | variable_value = "" 72 | event_node_path = NodePath("") 73 | event_subevents_quantity = 0 74 | 75 | [sub_resource type="Resource" id=8] 76 | resource_name = "Show" 77 | script = ExtResource( 9 ) 78 | continue_at_end = true 79 | method = "set" 80 | args = [ "visible", true ] 81 | event_node_path = NodePath("") 82 | event_subevents_quantity = 0 83 | 84 | [sub_resource type="Resource" id=9] 85 | resource_name = "Wait" 86 | script = ExtResource( 5 ) 87 | continue_at_end = true 88 | wait_time = 0.0 89 | event_node_path = NodePath("") 90 | event_subevents_quantity = 0 91 | 92 | [sub_resource type="Resource" id=10] 93 | resource_name = "Go to" 94 | script = ExtResource( 4 ) 95 | continue_at_end = true 96 | next_event = "" 97 | event_node_path = NodePath("") 98 | event_subevents_quantity = 0 99 | 100 | [resource] 101 | resource_name = "Timeline" 102 | script = ExtResource( 1 ) 103 | event/0 = SubResource( 1 ) 104 | event/1 = SubResource( 2 ) 105 | event/2 = SubResource( 3 ) 106 | event/3 = SubResource( 4 ) 107 | event/4 = SubResource( 5 ) 108 | event/5 = SubResource( 6 ) 109 | event/6 = SubResource( 7 ) 110 | event/7 = SubResource( 8 ) 111 | event/8 = SubResource( 9 ) 112 | event/9 = SubResource( 10 ) 113 | -------------------------------------------------------------------------------- /addons/event_system_plugin/resources/timeline_class/timeline_class.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Resource 3 | class_name Timeline, "res://addons/event_system_plugin/assets/icons/timeline_icon.png" 4 | 5 | ## 6 | ## Base class for all Timelines 7 | ## 8 | ## This resource only keeps an ordered reference of all events registered on it. 9 | 10 | # Can't reference: 11 | # - EventManager node 12 | # - Event 13 | # Note for future devs: Keep this resource as an event container. No magic tricks 14 | var _events:Array = [] setget set_events 15 | var _structure:Dictionary = {} 16 | 17 | ## Sets the event collection of this timeline. This replaces the current collection. 18 | func set_events(events:Array) -> void: 19 | _events = events 20 | emit_changed() 21 | property_list_changed_notify() 22 | 23 | ## Adds an event to the timeline. 24 | func add_event(event) -> void: 25 | if has(event): 26 | push_error("add_event: Trying to add an event to the timeline, but the event is already added") 27 | return 28 | 29 | _events.append(event) 30 | 31 | update_structure() 32 | emit_changed() 33 | property_list_changed_notify() 34 | 35 | ## Insert an [code]event[/code] at position. 36 | func insert_event(event, at_position:int) -> void: 37 | if has(event): 38 | push_error("insert_event: Trying to add an event to the timeline, but the event already exist") 39 | return 40 | 41 | var idx = at_position if at_position > -1 else _events.size() 42 | _events.insert(idx, event) 43 | 44 | update_structure() 45 | emit_changed() 46 | property_list_changed_notify() 47 | 48 | ## Moves an [code]event[/code] to position. 49 | func move_event(event, to_position:int) -> void: 50 | if !has(event): 51 | push_error("move_event: Trying to move an event in the timeline, but the event is not added.") 52 | return 53 | 54 | var old_position:int = get_event_idx(event) 55 | if old_position < 0: 56 | return 57 | 58 | to_position = to_position if to_position > -1 else _events.size() 59 | if to_position == old_position: 60 | emit_changed() 61 | return 62 | 63 | _events.remove(old_position) 64 | 65 | if to_position < 0 or to_position > _events.size(): 66 | to_position = _events.size() 67 | 68 | _events.insert(to_position, event) 69 | 70 | update_structure() 71 | emit_changed() 72 | property_list_changed_notify() 73 | 74 | 75 | ## Removes an event from the timeline. 76 | func erase_event(event) -> void: 77 | _events.erase(event) 78 | update_structure() 79 | emit_changed() 80 | property_list_changed_notify() 81 | 82 | ## Removes an event at [code]position[/code] from the timelin 83 | func remove_event(position:int) -> void: 84 | _events.remove(position) 85 | update_structure() 86 | emit_changed() 87 | property_list_changed_notify() 88 | 89 | ## Get the event at [code]position[/code] 90 | func get_event(position:int) -> Resource: 91 | if position == -1: 92 | return null 93 | 94 | if position < _events.size(): 95 | return _events[position] 96 | 97 | push_error("get_event: Tried to get an event on a non-existing position.") 98 | return null 99 | 100 | ## Returns [code]true[/code] if the [code]event[/code] is sub-event of [code]of_event[/code] 101 | func event_is_subevent_of(event, of_event) -> bool: 102 | if of_event in _structure: 103 | return event in _structure.get(of_event, []) 104 | return false 105 | 106 | ## Returns an array that contains the sub-events of [code]event[/code] 107 | func get_event_subevents(event) -> Array: 108 | var subevents:Array = [] 109 | if event in _structure: 110 | subevents = _structure.get(event, []) 111 | return subevents 112 | 113 | ## Updates the internal event structure. 114 | func update_structure() -> void: 115 | var subevent_holders := [] 116 | 117 | for event in _events: 118 | _structure[event] = [] 119 | event.set("event_subevent_from", null) 120 | event.set("event_indent_level", 0) 121 | if event.get("event_uses_subevents"): 122 | subevent_holders.append(event) 123 | 124 | _structure["subevent_holders"] = subevent_holders 125 | 126 | for event in subevent_holders: 127 | var from_here := false 128 | var sub_ev_counter := 0 129 | 130 | for sub_ev in _events: 131 | if from_here: 132 | sub_ev_counter += 1 133 | if sub_ev_counter > event.get("event_subevents_quantity"): 134 | break 135 | _structure[event].append(sub_ev) 136 | sub_ev.set("event_subevent_from", weakref(event)) 137 | sub_ev.set("event_indent_level", event.get("event_indent_level")+1) 138 | 139 | elif sub_ev != event: 140 | continue 141 | 142 | from_here = true 143 | 144 | if sub_ev_counter < 1: 145 | event.set("event_subevents_quantity", 0) 146 | 147 | ## Returns [code]true[/code] if the timeline contains that event. 148 | func has(event:Resource) -> bool: 149 | return _events.has(event) 150 | 151 | ## Returns the event position in the timeline. 152 | func get_event_idx(event) -> int: 153 | return _events.find(event) 154 | 155 | ## Returns an array containing the events of the timeline. 156 | func get_events() -> Array: 157 | return _events.duplicate() 158 | 159 | 160 | func _set(property:String, value) -> bool: 161 | var has_property := false 162 | 163 | if property.begins_with("event/"): 164 | var event_idx:int = int(property.split("/", true, 2)[1]) 165 | if event_idx < _events.size(): 166 | _events[event_idx] = value 167 | else: 168 | _events.insert(event_idx, value) 169 | 170 | has_property = true 171 | emit_changed() 172 | 173 | return has_property 174 | 175 | 176 | func _get(property:String): 177 | if property.begins_with("event/"): 178 | var event_idx:int = int(property.split("/", true, 2)[1]) 179 | if event_idx == -1: 180 | return null 181 | return get_event(event_idx) 182 | 183 | 184 | func _init() -> void: 185 | _events = [] 186 | _structure = {} 187 | resource_name = get_class() 188 | 189 | 190 | func _to_string() -> String: 191 | return "[{class}:{id}]".format({"class":get_class(), "id":get_instance_id()}) 192 | 193 | 194 | func get_class() -> String: return "Timeline" 195 | 196 | 197 | func _get_property_list() -> Array: 198 | var p = [] 199 | for event_idx in _events.size(): 200 | p.append( 201 | { 202 | "name":"event/{idx}".format({"idx":event_idx}), 203 | "type":TYPE_OBJECT, 204 | "usage":PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_SCRIPT_VARIABLE 205 | } 206 | ) 207 | return p 208 | --------------------------------------------------------------------------------