This commit is contained in:
TsubakiLoL 2024-10-25 15:41:39 +08:00
commit 960c397303
234 changed files with 9311 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Godot 4+ specific ignores
.godot/
/android/

View File

@ -0,0 +1,13 @@
Howdy! Thank you for downloading the Mystic Woods asset pack.
This is an ongoing project that I will be adding content to over time, so let me know if there's anything you'd like for me to create.
License - Free Version
- You can only use these assets in non-commercial projects.
- You can modify the assets.
- You can not redistribute or resale, even if modified.
Follow me on Twitter for updates on all of my projects.
https://twitter.com/GameEndeavor
If you enjoy this then leave a rating and comment. It helps to support this project!

View File

@ -0,0 +1,18 @@
Player and skeleton sprites are on a 48x48 grid.
Slime is on a 32x32 grid.
Flip right facing sprites to get the left facing sprites.
Animations [rows (0 based for us programmers)]
Player:
[0 - 2] idle
[3 - 5] move
[6 - 8] attack
[9] death
Enemies:
[0 - 2] idle
[3 - 5] move
[6 - 8] attack
[9 - 11] damaged
[12] death

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b8mr80al21rka"
path="res://.godot/imported/player.png-6c5d9809679900d37526f87878eeca81.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/characters/player.png"
dest_files=["res://.godot/imported/player.png-6c5d9809679900d37526f87878eeca81.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://csh4bp80n0jqu"
path="res://.godot/imported/skeleton.png-c741bdfc3b3bceef37fc96f2409dde34.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/characters/skeleton.png"
dest_files=["res://.godot/imported/skeleton.png-c741bdfc3b3bceef37fc96f2409dde34.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://qg24llaiojac"
path="res://.godot/imported/skeleton_swordless.png-cb67559e57d51e44b259e3220ec81f18.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/characters/skeleton_swordless.png"
dest_files=["res://.godot/imported/skeleton_swordless.png-cb67559e57d51e44b259e3220ec81f18.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cs24y4rmilkg6"
path="res://.godot/imported/slime.png-017622d32381f7a679938c4e151998ab.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/characters/slime.png"
dest_files=["res://.godot/imported/slime.png-017622d32381f7a679938c4e151998ab.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bgow2a3rs7q4j"
path="res://.godot/imported/chest_01.png-c2e99bfd7e7e892ed7f8651520769f4f.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/objects/chest_01.png"
dest_files=["res://.godot/imported/chest_01.png-c2e99bfd7e7e892ed7f8651520769f4f.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c5yvqfk63mcq8"
path="res://.godot/imported/chest_02.png-b6c6487f808784e97570961d0c4dfc50.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/objects/chest_02.png"
dest_files=["res://.godot/imported/chest_02.png-b6c6487f808784e97570961d0c4dfc50.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ox0pbgoe4gpa"
path="res://.godot/imported/objects.png-88a8f30761719fe7ea83996f3040f370.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/objects/objects.png"
dest_files=["res://.godot/imported/objects.png-88a8f30761719fe7ea83996f3040f370.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://hsr83f2epk1x"
path="res://.godot/imported/rock_in_water-sheet.png-494a098f01fbbb8d4eeab900b8b7f91b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/objects/rock_in_water-sheet.png"
dest_files=["res://.godot/imported/rock_in_water-sheet.png-494a098f01fbbb8d4eeab900b8b7f91b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://vt57eibv22qt"
path="res://.godot/imported/rock_in_water_01-sheet.png-7c5ed78fe97440039700ee7e4305fcf1.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/objects/rock_in_water_01-sheet.png"
dest_files=["res://.godot/imported/rock_in_water_01-sheet.png-7c5ed78fe97440039700ee7e4305fcf1.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cp73joxb56lep"
path="res://.godot/imported/rock_in_water_01.png-d49d566ddad27e087af789f831d1a4b5.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/objects/rock_in_water_01.png"
dest_files=["res://.godot/imported/rock_in_water_01.png-d49d566ddad27e087af789f831d1a4b5.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cw0fk2o5sdl5k"
path="res://.godot/imported/rock_in_water_02.png-532b7ae0b3325cc350e0ef0275c8a8cd.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/objects/rock_in_water_02.png"
dest_files=["res://.godot/imported/rock_in_water_02.png-532b7ae0b3325cc350e0ef0275c8a8cd.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://mr47gn76hwg7"
path="res://.godot/imported/rock_in_water_03.png-af0df681573d1e19c87e766443c69a92.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/objects/rock_in_water_03.png"
dest_files=["res://.godot/imported/rock_in_water_03.png-af0df681573d1e19c87e766443c69a92.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 675 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b7sxt5h40wjd8"
path="res://.godot/imported/rock_in_water_04.png-ba1e6f9c526e81869be3c6c84a5ff2ab.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/objects/rock_in_water_04.png"
dest_files=["res://.godot/imported/rock_in_water_04.png-ba1e6f9c526e81869be3c6c84a5ff2ab.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 680 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ck44rro1efn4c"
path="res://.godot/imported/rock_in_water_05.png-084ad4b304e8e3fa1e175b817b48e09b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/objects/rock_in_water_05.png"
dest_files=["res://.godot/imported/rock_in_water_05.png-084ad4b304e8e3fa1e175b817b48e09b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://kdvr8cdq1qtp"
path="res://.godot/imported/rock_in_water_06.png-f9656dc55bf81469416ee3cf6ecc193b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/objects/rock_in_water_06.png"
dest_files=["res://.godot/imported/rock_in_water_06.png-f9656dc55bf81469416ee3cf6ecc193b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d38emyi3bc20w"
path="res://.godot/imported/dust_particles_01.png-a6f4ecc279a7be030480bfba7330f796.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/particles/dust_particles_01.png"
dest_files=["res://.godot/imported/dust_particles_01.png-a6f4ecc279a7be030480bfba7330f796.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://84gy53ru31tj"
path="res://.godot/imported/decor_16x16.png-ebc18fc236a98a70e81737810ca73cd1.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/decor_16x16.png"
dest_files=["res://.godot/imported/decor_16x16.png-ebc18fc236a98a70e81737810ca73cd1.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c66txlefa0g1m"
path="res://.godot/imported/decor_8x8.png-8afa989d76666e299ba1bfa26b472e2e.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/decor_8x8.png"
dest_files=["res://.godot/imported/decor_8x8.png-8afa989d76666e299ba1bfa26b472e2e.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 722 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dqkj0y6pww0bc"
path="res://.godot/imported/fences.png-b9d16689c79f4ae187aad63d1e5a4689.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/fences.png"
dest_files=["res://.godot/imported/fences.png-b9d16689c79f4ae187aad63d1e5a4689.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://madjrbxrxb18"
path="res://.godot/imported/carpet.png-c7c1c7527f7abaa3bc874c3c2fc72934.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/floors/carpet.png"
dest_files=["res://.godot/imported/carpet.png-c7c1c7527f7abaa3bc874c3c2fc72934.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bdhd8cgpqqtqd"
path="res://.godot/imported/flooring.png-43d7f9ac4b16312ab64770bc17144840.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/floors/flooring.png"
dest_files=["res://.godot/imported/flooring.png-43d7f9ac4b16312ab64770bc17144840.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://t16xm66rao0u"
path="res://.godot/imported/wooden.png-d8637089a4903542d1c41347324bdeec.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/floors/wooden.png"
dest_files=["res://.godot/imported/wooden.png-d8637089a4903542d1c41347324bdeec.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://deevu4iws0aul"
path="res://.godot/imported/grass.png-b38d151724ddf2b6325fcfc9c526874c.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/grass.png"
dest_files=["res://.godot/imported/grass.png-b38d151724ddf2b6325fcfc9c526874c.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://br51oca80dq3i"
path="res://.godot/imported/plains.png-8fc6377fe63b8d212a1ec687887b3df5.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/plains.png"
dest_files=["res://.godot/imported/plains.png-8fc6377fe63b8d212a1ec687887b3df5.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ds5gmt2oas2j3"
path="res://.godot/imported/walls.png-2920d9fb288c762e49098bb246c0cd22.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/walls/walls.png"
dest_files=["res://.godot/imported/walls.png-2920d9fb288c762e49098bb246c0cd22.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://eobrojwn66mi"
path="res://.godot/imported/wooden_door.png-abc43f7cd3766c96e8f1fb22023e6b11.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/walls/wooden_door.png"
dest_files=["res://.godot/imported/wooden_door.png-abc43f7cd3766c96e8f1fb22023e6b11.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cerem13mn5ucr"
path="res://.godot/imported/wooden_door_b.png-b154ee80d2fc97a5c2957eb07c6f615b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/walls/wooden_door_b.png"
dest_files=["res://.godot/imported/wooden_door_b.png-b154ee80d2fc97a5c2957eb07c6f615b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://pg743cc5uv6g"
path="res://.godot/imported/water-sheet.png-97e1bd4345ba3193b9b0d736d3624019.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/water-sheet.png"
dest_files=["res://.godot/imported/water-sheet.png-97e1bd4345ba3193b9b0d736d3624019.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b740fvavkjn44"
path="res://.godot/imported/water1.png-6365ebf5cadbe6d647db816d6d87b5f2.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/water1.png"
dest_files=["res://.godot/imported/water1.png-6365ebf5cadbe6d647db816d6d87b5f2.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://djtnlgm0k15fg"
path="res://.godot/imported/water2.png-36a91ccfcca65406ba32a4f7f919f0e5.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/water2.png"
dest_files=["res://.godot/imported/water2.png-36a91ccfcca65406ba32a4f7f919f0e5.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bkku4jpjmesbb"
path="res://.godot/imported/water3.png-6fb7cc1c2a7f82ba36d70bae328646c7.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/water3.png"
dest_files=["res://.godot/imported/water3.png-6fb7cc1c2a7f82ba36d70bae328646c7.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dy5xp1e2kd156"
path="res://.godot/imported/water4.png-828fd72c261e630dc9cce3b5693f77c8.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/water4.png"
dest_files=["res://.godot/imported/water4.png-828fd72c261e630dc9cce3b5693f77c8.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ccf3j70kvu4rx"
path="res://.godot/imported/water5.png-e40c6a26d825c2c93b0d25a7f3fef30a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/water5.png"
dest_files=["res://.godot/imported/water5.png-e40c6a26d825c2c93b0d25a7f3fef30a.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dk5lb6o5iypcv"
path="res://.godot/imported/water6.png-ba003e892683f429157a8b6b2a450ec2.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/water6.png"
dest_files=["res://.godot/imported/water6.png-ba003e892683f429157a8b6b2a450ec2.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://vhtvtjpb6lgx"
path="res://.godot/imported/water_decorations.png-41081b5d89150170a462622f47f0db92.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/water_decorations.png"
dest_files=["res://.godot/imported/water_decorations.png-41081b5d89150170a462622f47f0db92.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b52dx8ej5geti"
path="res://.godot/imported/water_lillies.png-505badebc331d33e5ec126469a676a7a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://TEST/mystic_woods_free_2.2/sprites/tilesets/water_lillies.png"
dest_files=["res://.godot/imported/water_lillies.png-505badebc331d33e5ec126469a676a7a.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

21
addons/beehave/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 bitbrain
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,51 @@
@icon("icons/blackboard.svg")
class_name Blackboard extends Node
const DEFAULT = "default"
## The blackboard is an object that can be used to store and access data between
## multiple nodes of the behavior tree.
@export var blackboard: Dictionary = {}:
set(b):
blackboard = b
_data[DEFAULT] = blackboard
var _data: Dictionary = {}
func _ready():
_data[DEFAULT] = blackboard
func keys() -> Array[String]:
var keys: Array[String]
keys.assign(_data.keys().duplicate())
return keys
func set_value(key: Variant, value: Variant, blackboard_name: String = DEFAULT) -> void:
if not _data.has(blackboard_name):
_data[blackboard_name] = {}
_data[blackboard_name][key] = value
func get_value(
key: Variant, default_value: Variant = null, blackboard_name: String = DEFAULT
) -> Variant:
if has_value(key, blackboard_name):
return _data[blackboard_name].get(key, default_value)
return default_value
func has_value(key: Variant, blackboard_name: String = DEFAULT) -> bool:
return (
_data.has(blackboard_name)
and _data[blackboard_name].has(key)
and _data[blackboard_name][key] != null
)
func erase_value(key: Variant, blackboard_name: String = DEFAULT) -> void:
if _data.has(blackboard_name):
_data[blackboard_name][key] = null

View File

@ -0,0 +1,96 @@
@tool
extends EditorDebuggerPlugin
const DebuggerTab := preload("debugger_tab.gd")
const BeehaveUtils := preload("res://addons/beehave/utils/utils.gd")
var debugger_tab := DebuggerTab.new()
var floating_window: Window
var session: EditorDebuggerSession
func _has_capture(prefix: String) -> bool:
return prefix == "beehave"
func _capture(message: String, data: Array, session_id: int) -> bool:
# in case the behavior tree has invalid setup this might be null
if debugger_tab == null:
return false
if message == "beehave:register_tree":
debugger_tab.register_tree(data[0])
return true
if message == "beehave:unregister_tree":
debugger_tab.unregister_tree(data[0])
return true
if message == "beehave:process_tick":
debugger_tab.graph.process_tick(data[0], data[1])
return true
if message == "beehave:process_begin":
debugger_tab.graph.process_begin(data[0])
return true
if message == "beehave:process_end":
debugger_tab.graph.process_end(data[0])
return true
return false
func _setup_session(session_id: int) -> void:
session = get_session(session_id)
session.started.connect(debugger_tab.start)
session.stopped.connect(debugger_tab.stop)
debugger_tab.name = "🐝 Beehave"
debugger_tab.make_floating.connect(_on_make_floating)
debugger_tab.session = session
session.add_session_tab(debugger_tab)
func _on_make_floating() -> void:
var plugin := BeehaveUtils.get_plugin()
if not plugin:
return
if floating_window:
_on_window_close_requested()
return
var border_size := Vector2(4, 4) * BeehaveUtils.get_editor_scale()
var editor_interface: EditorInterface = plugin.get_editor_interface()
var editor_main_screen = editor_interface.get_editor_main_screen()
debugger_tab.get_parent().remove_child(debugger_tab)
floating_window = Window.new()
var panel := Panel.new()
panel.add_theme_stylebox_override(
"panel",
editor_interface.get_base_control().get_theme_stylebox("PanelForeground", "EditorStyles")
)
panel.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
floating_window.add_child(panel)
var margin := MarginContainer.new()
margin.add_child(debugger_tab)
margin.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
margin.add_theme_constant_override("margin_right", border_size.x)
margin.add_theme_constant_override("margin_left", border_size.x)
margin.add_theme_constant_override("margin_top", border_size.y)
margin.add_theme_constant_override("margin_bottom", border_size.y)
panel.add_child(margin)
floating_window.title = "🐝 Beehave"
floating_window.wrap_controls = true
floating_window.min_size = Vector2i(600, 350)
floating_window.size = debugger_tab.size
floating_window.position = editor_main_screen.global_position
floating_window.transient = true
floating_window.close_requested.connect(_on_window_close_requested)
editor_interface.get_base_control().add_child(floating_window)
func _on_window_close_requested() -> void:
debugger_tab.get_parent().remove_child(debugger_tab)
session.add_session_tab(debugger_tab)
floating_window.queue_free()
floating_window = null

View File

@ -0,0 +1,30 @@
class_name BeehaveDebuggerMessages
static func can_send_message() -> bool:
return not Engine.is_editor_hint() and OS.has_feature("editor")
static func register_tree(beehave_tree: Dictionary) -> void:
if can_send_message():
EngineDebugger.send_message("beehave:register_tree", [beehave_tree])
static func unregister_tree(instance_id: int) -> void:
if can_send_message():
EngineDebugger.send_message("beehave:unregister_tree", [instance_id])
static func process_tick(instance_id: int, status: int) -> void:
if can_send_message():
EngineDebugger.send_message("beehave:process_tick", [instance_id, status])
static func process_begin(instance_id: int) -> void:
if can_send_message():
EngineDebugger.send_message("beehave:process_begin", [instance_id])
static func process_end(instance_id: int) -> void:
if can_send_message():
EngineDebugger.send_message("beehave:process_end", [instance_id])

View File

@ -0,0 +1,125 @@
@tool
class_name BeehaveDebuggerTab extends PanelContainer
const BeehaveUtils := preload("res://addons/beehave/utils/utils.gd")
signal make_floating
const OldBeehaveGraphEdit := preload("old_graph_edit.gd")
const NewBeehaveGraphEdit := preload("new_graph_edit.gd")
const TREE_ICON := preload("../icons/tree.svg")
var graph
var container: HSplitContainer
var item_list: ItemList
var message: Label
var active_trees: Dictionary
var active_tree_id: int = -1
var session: EditorDebuggerSession
func _ready() -> void:
container = HSplitContainer.new()
add_child(container)
item_list = ItemList.new()
item_list.custom_minimum_size = Vector2(200, 0)
item_list.item_selected.connect(_on_item_selected)
container.add_child(item_list)
if Engine.get_version_info().minor >= 2:
graph = NewBeehaveGraphEdit.new(BeehaveUtils.get_frames())
else:
graph = OldBeehaveGraphEdit.new(BeehaveUtils.get_frames())
container.add_child(graph)
message = Label.new()
message.text = "Run Project for debugging"
message.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
message.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
message.set_anchors_preset(Control.PRESET_CENTER)
add_child(message)
var button := Button.new()
button.flat = true
button.name = "MakeFloatingButton"
button.icon = get_theme_icon(&"ExternalLink", &"EditorIcons")
button.pressed.connect(func(): make_floating.emit())
button.tooltip_text = "Make floating"
button.focus_mode = Control.FOCUS_NONE
graph.get_menu_container().add_child(button)
var toggle_button := Button.new()
toggle_button.flat = true
toggle_button.name = "TogglePanelButton"
toggle_button.icon = get_theme_icon(&"Back", &"EditorIcons")
toggle_button.pressed.connect(_on_toggle_button_pressed.bind(toggle_button))
toggle_button.tooltip_text = "Toggle Panel"
toggle_button.focus_mode = Control.FOCUS_NONE
graph.get_menu_container().add_child(toggle_button)
graph.get_menu_container().move_child(toggle_button, 0)
stop()
visibility_changed.connect(_on_visibility_changed)
func start() -> void:
container.visible = true
message.visible = false
func stop() -> void:
container.visible = false
message.visible = true
active_trees.clear()
item_list.clear()
graph.beehave_tree = {}
func register_tree(data: Dictionary) -> void:
if not active_trees.has(data.id):
var idx := item_list.add_item(data.name, TREE_ICON)
item_list.set_item_tooltip(idx, data.path)
item_list.set_item_metadata(idx, data.id)
active_trees[data.id] = data
if active_tree_id == data.id.to_int():
graph.beehave_tree = data
func unregister_tree(instance_id: int) -> void:
var id := str(instance_id)
for i in item_list.item_count:
if item_list.get_item_metadata(i) == id:
item_list.remove_item(i)
break
active_trees.erase(id)
if graph.beehave_tree.get("id", "") == id:
graph.beehave_tree = {}
func _on_toggle_button_pressed(toggle_button: Button) -> void:
item_list.visible = !item_list.visible
toggle_button.icon = get_theme_icon(
&"Back" if item_list.visible else &"Forward", &"EditorIcons"
)
func _on_item_selected(idx: int) -> void:
var id: StringName = item_list.get_item_metadata(idx)
graph.beehave_tree = active_trees.get(id, {})
active_tree_id = id.to_int()
if session != null:
session.send_message("beehave:activate_tree", [active_tree_id])
func _on_visibility_changed() -> void:
if session != null:
session.send_message("beehave:visibility_changed", [visible and is_visible_in_tree()])

View File

@ -0,0 +1,38 @@
extends Node
var _registered_trees: Dictionary
var _active_tree
func _enter_tree() -> void:
EngineDebugger.register_message_capture("beehave", _on_debug_message)
func _on_debug_message(message: String, data: Array) -> bool:
if message == "activate_tree":
_set_active_tree(data[0])
return true
if message == "visibility_changed":
if _active_tree && is_instance_valid(_active_tree):
_active_tree._can_send_message = data[0]
return true
return false
func _set_active_tree(tree_id: int) -> void:
var tree = _registered_trees.get(tree_id, null)
if not tree:
return
if _active_tree && is_instance_valid(_active_tree):
_active_tree._can_send_message = false
_active_tree = tree
_active_tree._can_send_message = true
func register_tree(tree) -> void:
_registered_trees[tree.get_instance_id()] = tree
func unregister_tree(tree) -> void:
_registered_trees.erase(tree.get_instance_id())

View File

@ -0,0 +1 @@
<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="matrix(0 -1 1 0 0 16)"><rect height="6" rx="1" stroke-width=".6" width="6" y="10"/><rect height="6" rx="1" stroke-width=".780723" width="6" x="5"/><rect height="6" rx="1" stroke-width=".780723" width="6" x="10" y="10"/><path d="m7 5h2v4h-2z" stroke-width=".768491"/><rect height="4" rx="1" ry="0" stroke-width=".768491" width="2" x="12" y="7"/><rect height="5" rx="1" stroke-width=".859" width="2" x="2" y="7"/><path d="m3 7h10v2h-10z" stroke-width="1.09113"/></g></svg>

After

Width:  |  Height:  |  Size: 562 B

View File

@ -0,0 +1,38 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bah77esichnyx"
path="res://.godot/imported/horizontal_layout.svg-d2a7af351e44f9bf61d0c938b6f47fac.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/debug/icons/horizontal_layout.svg"
dest_files=["res://.godot/imported/horizontal_layout.svg-d2a7af351e44f9bf61d0c938b6f47fac.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=true

View File

@ -0,0 +1 @@
<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><path d="m10 4a5 5 0 0 1 -2.5000001 4.3301271 5 5 0 0 1 -5-.0000002 5 5 0 0 1 -2.4999999-4.3301269" fill="#fff" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 222 B

View File

@ -0,0 +1,38 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://da3b236rjbqns"
path="res://.godot/imported/port_bottom.svg-e5c5c61b642a79ab9c2b66ff56603d34.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/debug/icons/port_bottom.svg"
dest_files=["res://.godot/imported/port_bottom.svg-e5c5c61b642a79ab9c2b66ff56603d34.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=true

View File

@ -0,0 +1 @@
<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><path d="m5 0a5 5 0 0 0 -4.33012712 2.5000001 5 5 0 0 0 .0000002 5 5 5 0 0 0 4.33012692 2.4999999" fill="#fff" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 221 B

View File

@ -0,0 +1,38 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bnufc8p6spdtn"
path="res://.godot/imported/port_left.svg-69cd927c4db555f1edbb8d1f553ea2fd.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/debug/icons/port_left.svg"
dest_files=["res://.godot/imported/port_left.svg-69cd927c4db555f1edbb8d1f553ea2fd.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=true

View File

@ -0,0 +1 @@
<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><path d="m4.5 10a5 5 0 0 0 4.3301271-2.5000002 5 5 0 0 0 -.0000002-4.9999999 5 5 0 0 0 -4.3301269-2.4999999" fill="#fff" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 231 B

View File

@ -0,0 +1,38 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bbmd6vk23ympm"
path="res://.godot/imported/port_right.svg-f760bd8be2dd613d0d3848c998c92a2a.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/debug/icons/port_right.svg"
dest_files=["res://.godot/imported/port_right.svg-f760bd8be2dd613d0d3848c998c92a2a.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=true

View File

@ -0,0 +1 @@
<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><path d="m10-6a5 5 0 0 1 -2.5000001 4.3301271 5 5 0 0 1 -5-.0000002 5 5 0 0 1 -2.4999999-4.3301269" fill="#fff" fill-rule="evenodd" transform="scale(1 -1)"/></svg>

After

Width:  |  Height:  |  Size: 246 B

View File

@ -0,0 +1,38 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bw8wmxdfom8eh"
path="res://.godot/imported/port_top.svg-d1b336cdc6a0dd570305782a1e56f61d.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/debug/icons/port_top.svg"
dest_files=["res://.godot/imported/port_top.svg-d1b336cdc6a0dd570305782a1e56f61d.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=true

View File

@ -0,0 +1 @@
<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><rect height="6" rx="1" stroke-width=".6" width="6" y="10"/><rect height="6" rx="1" stroke-width=".780723" width="6" x="5"/><rect height="6" rx="1" stroke-width=".780723" width="6" x="10" y="10"/><path d="m7 5h2v4h-2z" stroke-width=".768491"/><rect height="4" rx="1" ry="0" stroke-width=".768491" width="2" x="12" y="7"/><rect height="5" rx="1" stroke-width=".859" width="2" x="2" y="7"/><path d="m3 7h10v2h-10z" stroke-width="1.09113"/></g></svg>

After

Width:  |  Height:  |  Size: 528 B

View File

@ -0,0 +1,38 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bpyxu6i1dx5qh"
path="res://.godot/imported/vertical_layout.svg-1a08fee4b09812a05bcf3defb8afcc4c.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/debug/icons/vertical_layout.svg"
dest_files=["res://.godot/imported/vertical_layout.svg-1a08fee4b09812a05bcf3defb8afcc4c.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=true

View File

@ -0,0 +1,69 @@
@tool
extends RefCounted
const BeehaveUtils := preload("res://addons/beehave/utils/utils.gd")
const SUCCESS_COLOR := Color("#07783a")
const NORMAL_COLOR := Color("#15181e")
const FAILURE_COLOR := Color("#82010b")
const RUNNING_COLOR := Color("#c29c06")
var panel_normal: StyleBoxFlat
var panel_success: StyleBoxFlat
var panel_failure: StyleBoxFlat
var panel_running: StyleBoxFlat
var titlebar_normal: StyleBoxFlat
var titlebar_success: StyleBoxFlat
var titlebar_failure: StyleBoxFlat
var titlebar_running: StyleBoxFlat
func _init() -> void:
var plugin := BeehaveUtils.get_plugin()
if not plugin:
return
titlebar_normal = (
plugin
.get_editor_interface()
.get_base_control()
.get_theme_stylebox(&"titlebar", &"GraphNode")\
.duplicate()
)
titlebar_success = titlebar_normal.duplicate()
titlebar_failure = titlebar_normal.duplicate()
titlebar_running = titlebar_normal.duplicate()
titlebar_success.bg_color = SUCCESS_COLOR
titlebar_failure.bg_color = FAILURE_COLOR
titlebar_running.bg_color = RUNNING_COLOR
titlebar_success.border_color = SUCCESS_COLOR
titlebar_failure.border_color = FAILURE_COLOR
titlebar_running.border_color = RUNNING_COLOR
panel_normal = (
plugin
.get_editor_interface()
.get_base_control()
.get_theme_stylebox(&"panel", &"GraphNode")
.duplicate()
)
panel_success = (
plugin
.get_editor_interface()
.get_base_control()
.get_theme_stylebox(&"panel_selected", &"GraphNode")
.duplicate()
)
panel_failure = panel_success.duplicate()
panel_running = panel_success.duplicate()
panel_success.border_color = SUCCESS_COLOR
panel_failure.border_color = FAILURE_COLOR
panel_running.border_color = RUNNING_COLOR

View File

@ -0,0 +1,296 @@
@tool
extends GraphEdit
const BeehaveGraphNode := preload("new_graph_node.gd")
const HORIZONTAL_LAYOUT_ICON := preload("icons/horizontal_layout.svg")
const VERTICAL_LAYOUT_ICON := preload("icons/vertical_layout.svg")
const PROGRESS_SHIFT: int = 50
const INACTIVE_COLOR: Color = Color("#898989")
const ACTIVE_COLOR: Color = Color("#c29c06")
const SUCCESS_COLOR: Color = Color("#07783a")
var updating_graph: bool = false
var arraging_nodes: bool = false
var beehave_tree: Dictionary:
set(value):
if beehave_tree == value:
return
beehave_tree = value
active_nodes.clear()
_update_graph()
var horizontal_layout: bool = false:
set(value):
if updating_graph or arraging_nodes:
return
if horizontal_layout == value:
return
horizontal_layout = value
_update_layout_button()
_update_graph()
var frames:RefCounted
var active_nodes: Array[String]
var progress: int = 0
var layout_button: Button
func _init(frames:RefCounted) -> void:
self.frames = frames
func _ready() -> void:
custom_minimum_size = Vector2(100, 300)
set("show_arrange_button", true)
minimap_enabled = false
layout_button = Button.new()
layout_button.flat = true
layout_button.focus_mode = Control.FOCUS_NONE
layout_button.pressed.connect(func(): horizontal_layout = not horizontal_layout)
get_menu_container().add_child(layout_button)
_update_layout_button()
func _update_graph() -> void:
if updating_graph:
return
updating_graph = true
clear_connections()
for child in _get_child_nodes():
remove_child(child)
child.queue_free()
if not beehave_tree.is_empty():
_add_nodes(beehave_tree)
_connect_nodes(beehave_tree)
_arrange_nodes.call_deferred(beehave_tree)
updating_graph = false
func _add_nodes(node: Dictionary) -> void:
if node.is_empty():
return
var gnode := BeehaveGraphNode.new(frames, horizontal_layout)
add_child(gnode)
gnode.title_text = node.name
gnode.name = node.id
gnode.icon = _get_icon(node.type.back())
if node.type.has(&"BeehaveTree"):
gnode.set_slots(false, true)
elif node.type.has(&"Leaf"):
gnode.set_slots(true, false)
elif node.type.has(&"Composite") or node.type.has(&"Decorator"):
gnode.set_slots(true, true)
for child in node.get("children", []):
_add_nodes(child)
func _connect_nodes(node: Dictionary) -> void:
for child in node.get("children", []):
connect_node(node.id, 0, child.id, 0)
_connect_nodes(child)
func _arrange_nodes(node: Dictionary) -> void:
if arraging_nodes:
return
arraging_nodes = true
var tree_node := _create_tree_nodes(node)
tree_node.update_positions(horizontal_layout)
_place_nodes(tree_node)
arraging_nodes = false
func _create_tree_nodes(node: Dictionary, root: TreeNode = null) -> TreeNode:
var tree_node := TreeNode.new(get_node(node.id), root)
for child in node.get("children", []):
var child_node := _create_tree_nodes(child, tree_node)
tree_node.children.push_back(child_node)
return tree_node
func _place_nodes(node: TreeNode) -> void:
node.item.position_offset = Vector2(node.x, node.y)
for child in node.children:
_place_nodes(child)
func _get_icon(type: StringName) -> Texture2D:
var classes := ProjectSettings.get_global_class_list()
for c in classes:
if c["class"] == type:
var icon_path := c.get("icon", String())
if not icon_path.is_empty():
return load(icon_path)
return null
func get_menu_container() -> Control:
return call("get_menu_hbox")
func get_status(status: int) -> String:
if status == 0:
return "SUCCESS"
elif status == 1:
return "FAILURE"
return "RUNNING"
func process_begin(instance_id: int) -> void:
if not _is_same_tree(instance_id):
return
for child in _get_child_nodes():
child.set_meta("status", -1)
func process_tick(instance_id: int, status: int) -> void:
var node := get_node_or_null(str(instance_id))
if node:
node.text = "Status: %s" % get_status(status)
node.set_status(status)
node.set_meta("status", status)
if status == 0 or status == 2:
if not active_nodes.has(node.name):
active_nodes.push_back(node.name)
func process_end(instance_id: int) -> void:
if not _is_same_tree(instance_id):
return
for child in _get_child_nodes():
var status := child.get_meta("status", -1)
match status:
0:
active_nodes.erase(child.name)
child.set_color(SUCCESS_COLOR)
1:
active_nodes.erase(child.name)
child.set_color(INACTIVE_COLOR)
2:
child.set_color(ACTIVE_COLOR)
_:
child.text = " "
child.set_status(status)
child.set_color(INACTIVE_COLOR)
func _is_same_tree(instance_id: int) -> bool:
return str(instance_id) == beehave_tree.get("id", "")
func _get_child_nodes() -> Array[Node]:
return get_children().filter(func(child): return child is BeehaveGraphNode)
func _get_connection_line(from_position: Vector2, to_position: Vector2) -> PackedVector2Array:
for child in _get_child_nodes():
for port in child.get_input_port_count():
if not (child.position_offset + child.get_input_port_position(port)).is_equal_approx(to_position):
continue
to_position = child.position_offset + child.get_custom_input_port_position(horizontal_layout)
for port in child.get_output_port_count():
if not (child.position_offset + child.get_output_port_position(port)).is_equal_approx(from_position):
continue
from_position = child.position_offset + child.get_custom_output_port_position(horizontal_layout)
return _get_elbow_connection_line(from_position, to_position)
func _get_elbow_connection_line(from_position: Vector2, to_position: Vector2) -> PackedVector2Array:
var points: PackedVector2Array
points.push_back(from_position)
var mid_position := ((to_position + from_position) / 2).round()
if horizontal_layout:
points.push_back(Vector2(mid_position.x, from_position.y))
points.push_back(Vector2(mid_position.x, to_position.y))
else:
points.push_back(Vector2(from_position.x, mid_position.y))
points.push_back(Vector2(to_position.x, mid_position.y))
points.push_back(to_position)
return points
func _process(delta: float) -> void:
if not active_nodes.is_empty():
progress += 10 if delta >= 0.05 else 1
if progress >= 1000:
progress = 0
queue_redraw()
func _draw() -> void:
if active_nodes.is_empty():
return
var circle_size: float = max(3, 6 * zoom)
var progress_shift: float = PROGRESS_SHIFT * zoom
var connections := get_connection_list()
for c in connections:
var from_node: StringName
var to_node: StringName
from_node = c.from_node
to_node = c.to_node
if not from_node in active_nodes or not c.to_node in active_nodes:
continue
var from := get_node(String(from_node))
var to := get_node(String(to_node))
if from.get_meta("status", -1) < 0 or to.get_meta("status", -1) < 0:
return
var output_port_position: Vector2
var input_port_position: Vector2
var scale_factor: float = from.get_rect().size.x / from.size.x
var line := _get_elbow_connection_line(
from.position + from.get_custom_output_port_position(horizontal_layout) * scale_factor,
to.position + to.get_custom_input_port_position(horizontal_layout) * scale_factor
)
var curve = Curve2D.new()
for l in line:
curve.add_point(l)
var max_steps := int(curve.get_baked_length())
var current_shift := progress % max_steps
var p := curve.sample_baked(current_shift)
draw_circle(p, circle_size, ACTIVE_COLOR)
var shift := current_shift - progress_shift
while shift >= 0:
draw_circle(curve.sample_baked(shift), circle_size, ACTIVE_COLOR)
shift -= progress_shift
shift = current_shift + progress_shift
while shift <= curve.get_baked_length():
draw_circle(curve.sample_baked(shift), circle_size, ACTIVE_COLOR)
shift += progress_shift
func _update_layout_button() -> void:
layout_button.icon = VERTICAL_LAYOUT_ICON if horizontal_layout else HORIZONTAL_LAYOUT_ICON
layout_button.tooltip_text = "Switch to Vertical layout" if horizontal_layout else "Switch to Horizontal layout"

View File

@ -0,0 +1,155 @@
@tool
extends GraphNode
const BeehaveUtils := preload("res://addons/beehave/utils/utils.gd")
const PORT_TOP_ICON := preload("icons/port_top.svg")
const PORT_BOTTOM_ICON := preload("icons/port_bottom.svg")
const PORT_LEFT_ICON := preload("icons/port_left.svg")
const PORT_RIGHT_ICON := preload("icons/port_right.svg")
@export var title_text: String:
set(value):
title_text = value
if title_label:
title_label.text = value
@export var text: String:
set(value):
text = value
if label:
label.text = " " if text.is_empty() else text
@export var icon: Texture2D:
set(value):
icon = value
if icon_rect:
icon_rect.texture = value
var layout_size: float:
get:
return size.y if horizontal else size.x
var icon_rect: TextureRect
var title_label: Label
var label: Label
var titlebar_hbox: HBoxContainer
var frames: RefCounted
var horizontal: bool = false
func _init(frames:RefCounted, horizontal: bool = false) -> void:
self.frames = frames
self.horizontal = horizontal
func _ready() -> void:
custom_minimum_size = Vector2(50, 50) * BeehaveUtils.get_editor_scale()
draggable = false
add_theme_color_override("close_color", Color.TRANSPARENT)
add_theme_icon_override("close", ImageTexture.new())
# For top port
var top_port: Control = Control.new()
add_child(top_port)
icon_rect = TextureRect.new()
icon_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
titlebar_hbox = get_titlebar_hbox()
titlebar_hbox.get_child(0).queue_free()
titlebar_hbox.alignment = BoxContainer.ALIGNMENT_BEGIN
titlebar_hbox.add_child(icon_rect)
title_label = Label.new()
title_label.add_theme_color_override("font_color", Color.WHITE)
var title_font: Font = get_theme_font("title_font").duplicate()
if title_font is FontVariation:
title_font.variation_embolden = 1
elif title_font is FontFile:
title_font.font_weight = 700
title_label.add_theme_font_override("font", title_font)
title_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
title_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
title_label.text = title_text
titlebar_hbox.add_child(title_label)
label = Label.new()
label.text = " " if text.is_empty() else text
add_child(label)
# For bottom port
add_child(Control.new())
minimum_size_changed.connect(_on_size_changed)
_on_size_changed.call_deferred()
func _draw_port(slot_index: int, port_position: Vector2i, left: bool, color: Color) -> void:
if horizontal:
if is_slot_enabled_left(1):
draw_texture(PORT_LEFT_ICON, Vector2(0, size.y / 2) + Vector2(-4, -5), color)
if is_slot_enabled_right(1):
draw_texture(PORT_RIGHT_ICON, Vector2(size.x, size.y / 2) + Vector2(-5, -4.5), color)
else:
if slot_index == 0 and is_slot_enabled_left(0):
draw_texture(PORT_TOP_ICON, Vector2(size.x / 2, 0) + Vector2(-4.5, -7), color)
elif slot_index == 1:
draw_texture(PORT_BOTTOM_ICON, Vector2(size.x / 2, size.y) + Vector2(-4.5, -5), color)
func get_custom_input_port_position(horizontal: bool) -> Vector2:
if horizontal:
return Vector2(0, size.y / 2)
else:
return Vector2(size.x/2, 0)
func get_custom_output_port_position(horizontal: bool) -> Vector2:
if horizontal:
return Vector2(size.x, size.y / 2)
else:
return Vector2(size.x / 2, size.y)
func set_status(status: int) -> void:
match status:
0: _set_stylebox_overrides(frames.panel_success, frames.titlebar_success)
1: _set_stylebox_overrides(frames.panel_failure, frames.titlebar_failure)
2: _set_stylebox_overrides(frames.panel_running, frames.titlebar_running)
_: _set_stylebox_overrides(frames.panel_normal, frames.titlebar_normal)
func set_slots(left_enabled: bool, right_enabled: bool) -> void:
if horizontal:
set_slot(1, left_enabled, -1, Color.WHITE, right_enabled, -1, Color.WHITE, PORT_LEFT_ICON, PORT_RIGHT_ICON)
else:
set_slot(0, left_enabled, -1, Color.WHITE, false, -1, Color.TRANSPARENT, PORT_TOP_ICON, null)
set_slot(2, false, -1, Color.TRANSPARENT, right_enabled, -1, Color.WHITE, null, PORT_BOTTOM_ICON)
func set_color(color: Color) -> void:
set_input_color(color)
set_output_color(color)
func set_input_color(color: Color) -> void:
set_slot_color_left(1 if horizontal else 0, color)
func set_output_color(color: Color) -> void:
set_slot_color_right(1 if horizontal else 2, color)
func _set_stylebox_overrides(panel_stylebox: StyleBox, titlebar_stylebox: StyleBox) -> void:
add_theme_stylebox_override("panel", panel_stylebox)
add_theme_stylebox_override("titlebar", titlebar_stylebox)
func _on_size_changed():
add_theme_constant_override("port_offset", 12 * BeehaveUtils.get_editor_scale() if horizontal else round(size.x))

View File

@ -0,0 +1,47 @@
@tool
extends RefCounted
const BeehaveUtils := preload("res://addons/beehave/utils/utils.gd")
const SUCCESS_COLOR := Color("#009944c8")
const NORMAL_COLOR := Color("#15181e")
const FAILURE_COLOR := Color("#cf000f80")
const RUNNING_COLOR := Color("#ffcc00c8")
var empty: StyleBoxEmpty
var normal: StyleBoxFlat
var success: StyleBoxFlat
var failure: StyleBoxFlat
var running: StyleBoxFlat
func _init() -> void:
var plugin := BeehaveUtils.get_plugin()
if not plugin:
return
var editor_scale := BeehaveUtils.get_editor_scale()
empty = StyleBoxEmpty.new()
normal = (
plugin
. get_editor_interface()
. get_base_control()
. get_theme_stylebox(&"frame", &"GraphNode")
. duplicate()
)
success = (
plugin
. get_editor_interface()
. get_base_control()
. get_theme_stylebox(&"selected_frame", &"GraphNode")
. duplicate()
)
failure = success.duplicate()
running = success.duplicate()
success.border_color = SUCCESS_COLOR
failure.border_color = FAILURE_COLOR
running.border_color = RUNNING_COLOR

View File

@ -0,0 +1,286 @@
@tool
extends GraphEdit
const BeehaveGraphNode := preload("old_graph_node.gd")
const HORIZONTAL_LAYOUT_ICON := preload("icons/horizontal_layout.svg")
const VERTICAL_LAYOUT_ICON := preload("icons/vertical_layout.svg")
const PROGRESS_SHIFT: int = 50
const INACTIVE_COLOR: Color = Color("#898989aa")
const ACTIVE_COLOR: Color = Color("#ffcc00c8")
const SUCCESS_COLOR: Color = Color("#009944c8")
var updating_graph: bool = false
var arraging_nodes: bool = false
var beehave_tree: Dictionary:
set(value):
if beehave_tree == value:
return
beehave_tree = value
active_nodes.clear()
_update_graph()
var horizontal_layout: bool = false:
set(value):
if updating_graph or arraging_nodes:
return
if horizontal_layout == value:
return
horizontal_layout = value
_update_layout_button()
_update_graph()
var frames: RefCounted
var active_nodes: Array[String]
var progress: int = 0
var layout_button: Button
func _init(frames: RefCounted) -> void:
self.frames = frames
func _ready() -> void:
custom_minimum_size = Vector2(100, 300)
set("arrange_nodes_button_hidden", true)
minimap_enabled = false
layout_button = Button.new()
layout_button.flat = true
layout_button.focus_mode = Control.FOCUS_NONE
layout_button.pressed.connect(func(): horizontal_layout = not horizontal_layout)
get_menu_container().add_child(layout_button)
_update_layout_button()
func _update_graph() -> void:
if updating_graph:
return
updating_graph = true
clear_connections()
for child in _get_child_nodes():
remove_child(child)
child.queue_free()
if not beehave_tree.is_empty():
_add_nodes(beehave_tree)
_connect_nodes(beehave_tree)
_arrange_nodes.call_deferred(beehave_tree)
updating_graph = false
func _add_nodes(node: Dictionary) -> void:
if node.is_empty():
return
var gnode := BeehaveGraphNode.new(frames, horizontal_layout)
add_child(gnode)
gnode.title_text = node.name
gnode.name = node.id
gnode.icon = _get_icon(node.type.back())
if node.type.has(&"BeehaveTree"):
gnode.set_slots(false, true)
elif node.type.has(&"Leaf"):
gnode.set_slots(true, false)
elif node.type.has(&"Composite") or node.type.has(&"Decorator"):
gnode.set_slots(true, true)
for child in node.get("children", []):
_add_nodes(child)
func _connect_nodes(node: Dictionary) -> void:
for child in node.get("children", []):
connect_node(node.id, 0, child.id, 0)
_connect_nodes(child)
func _arrange_nodes(node: Dictionary) -> void:
if arraging_nodes:
return
arraging_nodes = true
var tree_node := _create_tree_nodes(node)
tree_node.update_positions(horizontal_layout)
_place_nodes(tree_node)
arraging_nodes = false
func _create_tree_nodes(node: Dictionary, root: TreeNode = null) -> TreeNode:
var tree_node := TreeNode.new(get_node(node.id), root)
for child in node.get("children", []):
var child_node := _create_tree_nodes(child, tree_node)
tree_node.children.push_back(child_node)
return tree_node
func _place_nodes(node: TreeNode) -> void:
node.item.position_offset = Vector2(node.x, node.y)
for child in node.children:
_place_nodes(child)
func _get_icon(type: StringName) -> Texture2D:
var classes := ProjectSettings.get_global_class_list()
for c in classes:
if c["class"] == type:
var icon_path := c.get("icon", String())
if not icon_path.is_empty():
return load(icon_path)
return null
func get_menu_container() -> Control:
return call("get_zoom_hbox")
func get_status(status: int) -> String:
if status == 0:
return "SUCCESS"
elif status == 1:
return "FAILURE"
return "RUNNING"
func process_begin(instance_id: int) -> void:
if not _is_same_tree(instance_id):
return
for child in _get_child_nodes():
child.set_meta("status", -1)
func process_tick(instance_id: int, status: int) -> void:
var node := get_node_or_null(str(instance_id))
if node:
node.text = "Status: %s" % get_status(status)
node.set_status(status)
node.set_meta("status", status)
if status == 0 or status == 2:
if not active_nodes.has(node.name):
active_nodes.push_back(node.name)
func process_end(instance_id: int) -> void:
if not _is_same_tree(instance_id):
return
for child in _get_child_nodes():
var status := child.get_meta("status", -1)
match status:
0:
active_nodes.erase(child.name)
child.set_color(SUCCESS_COLOR)
1:
active_nodes.erase(child.name)
child.set_color(INACTIVE_COLOR)
2:
child.set_color(ACTIVE_COLOR)
_:
child.text = " "
child.set_status(status)
child.set_color(INACTIVE_COLOR)
func _is_same_tree(instance_id: int) -> bool:
return str(instance_id) == beehave_tree.get("id", "")
func _get_child_nodes() -> Array[Node]:
return get_children().filter(func(child): return child is BeehaveGraphNode)
func _get_connection_line(from_position: Vector2, to_position: Vector2) -> PackedVector2Array:
var points: PackedVector2Array
from_position = from_position.round()
to_position = to_position.round()
points.push_back(from_position)
var mid_position := ((to_position + from_position) / 2).round()
if horizontal_layout:
points.push_back(Vector2(mid_position.x, from_position.y))
points.push_back(Vector2(mid_position.x, to_position.y))
else:
points.push_back(Vector2(from_position.x, mid_position.y))
points.push_back(Vector2(to_position.x, mid_position.y))
points.push_back(to_position)
return points
func _process(delta: float) -> void:
if not active_nodes.is_empty():
progress += 10 if delta >= 0.05 else 1
if progress >= 1000:
progress = 0
queue_redraw()
func _draw() -> void:
if active_nodes.is_empty():
return
var circle_size: float = max(3, 6 * zoom)
var progress_shift: float = PROGRESS_SHIFT * zoom
var connections := get_connection_list()
for c in connections:
var from_node: StringName
var to_node: StringName
from_node = c.from
to_node = c.to
if not from_node in active_nodes or not c.to_node in active_nodes:
continue
var from := get_node(String(from_node))
var to := get_node(String(to_node))
if from.get_meta("status", -1) < 0 or to.get_meta("status", -1) < 0:
return
var output_port_position: Vector2
var input_port_position: Vector2
output_port_position = (
from.position + from.call("get_connection_output_position", c.from_port)
)
input_port_position = to.position + to.call("get_connection_input_position", c.to_port)
var line := _get_connection_line(output_port_position, input_port_position)
var curve = Curve2D.new()
for l in line:
curve.add_point(l)
var max_steps := int(curve.get_baked_length())
var current_shift := progress % max_steps
var p := curve.sample_baked(current_shift)
draw_circle(p, circle_size, ACTIVE_COLOR)
var shift := current_shift - progress_shift
while shift >= 0:
draw_circle(curve.sample_baked(shift), circle_size, ACTIVE_COLOR)
shift -= progress_shift
shift = current_shift + progress_shift
while shift <= curve.get_baked_length():
draw_circle(curve.sample_baked(shift), circle_size, ACTIVE_COLOR)
shift += progress_shift
func _update_layout_button() -> void:
layout_button.icon = VERTICAL_LAYOUT_ICON if horizontal_layout else HORIZONTAL_LAYOUT_ICON
layout_button.tooltip_text = (
"Switch to Vertical layout" if horizontal_layout else "Switch to Horizontal layout"
)

View File

@ -0,0 +1,166 @@
@tool
extends GraphNode
const BeehaveUtils := preload("res://addons/beehave/utils/utils.gd")
const DEFAULT_COLOR := Color("#dad4cb")
const PORT_TOP_ICON := preload("icons/port_top.svg")
const PORT_BOTTOM_ICON := preload("icons/port_bottom.svg")
const PORT_LEFT_ICON := preload("icons/port_left.svg")
const PORT_RIGHT_ICON := preload("icons/port_right.svg")
@export var title_text: String:
set(value):
title_text = value
if title_label:
title_label.text = value
@export var text: String:
set(value):
text = value
if label:
label.text = " " if text.is_empty() else text
@export var icon: Texture2D:
set(value):
icon = value
if icon_rect:
icon_rect.texture = value
var layout_size: float:
get:
return size.y if horizontal else size.x
var panel: PanelContainer
var icon_rect: TextureRect
var title_label: Label
var container: VBoxContainer
var label: Label
var frames: RefCounted
var horizontal: bool = false
func _init(frames: RefCounted, horizontal: bool = false) -> void:
self.frames = frames
self.horizontal = horizontal
func _ready() -> void:
custom_minimum_size = Vector2(50, 50) * BeehaveUtils.get_editor_scale()
draggable = false
add_theme_stylebox_override("frame", frames.empty if frames != null else null)
add_theme_stylebox_override("selected_frame", frames.empty if frames != null else null)
add_theme_color_override("close_color", Color.TRANSPARENT)
add_theme_icon_override("close", ImageTexture.new())
# For top port
add_child(Control.new())
panel = PanelContainer.new()
panel.mouse_filter = Control.MOUSE_FILTER_PASS
panel.add_theme_stylebox_override("panel", frames.normal if frames != null else null)
add_child(panel)
var vbox_container := VBoxContainer.new()
panel.add_child(vbox_container)
var title_size := 24 * BeehaveUtils.get_editor_scale()
var margin_container := MarginContainer.new()
margin_container.add_theme_constant_override(
"margin_top", -title_size - 2 * BeehaveUtils.get_editor_scale()
)
margin_container.mouse_filter = Control.MOUSE_FILTER_PASS
vbox_container.add_child(margin_container)
var title_container := HBoxContainer.new()
title_container.add_child(Control.new())
title_container.mouse_filter = Control.MOUSE_FILTER_PASS
title_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
margin_container.add_child(title_container)
icon_rect = TextureRect.new()
icon_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
title_container.add_child(icon_rect)
title_label = Label.new()
title_label.add_theme_color_override("font_color", DEFAULT_COLOR)
title_label.add_theme_font_override("font", get_theme_font("title_font"))
title_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
title_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
title_label.text = title_text
title_container.add_child(title_label)
title_container.add_child(Control.new())
container = VBoxContainer.new()
container.size_flags_vertical = Control.SIZE_EXPAND_FILL
container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
panel.add_child(container)
label = Label.new()
label.text = " " if text.is_empty() else text
container.add_child(label)
# For bottom port
add_child(Control.new())
minimum_size_changed.connect(_on_size_changed)
_on_size_changed.call_deferred()
func set_status(status: int) -> void:
panel.add_theme_stylebox_override("panel", _get_stylebox(status))
func _get_stylebox(status: int) -> StyleBox:
match status:
0:
return frames.success
1:
return frames.failure
2:
return frames.running
_:
return frames.normal
func set_slots(left_enabled: bool, right_enabled: bool) -> void:
if horizontal:
set_slot(
1,
left_enabled,
0,
Color.WHITE,
right_enabled,
0,
Color.WHITE,
PORT_LEFT_ICON,
PORT_RIGHT_ICON
)
else:
set_slot(0, left_enabled, 0, Color.WHITE, false, -2, Color.TRANSPARENT, PORT_TOP_ICON, null)
set_slot(
2, false, -1, Color.TRANSPARENT, right_enabled, 0, Color.WHITE, null, PORT_BOTTOM_ICON
)
func set_color(color: Color) -> void:
set_input_color(color)
set_output_color(color)
func set_input_color(color: Color) -> void:
set_slot_color_left(1 if horizontal else 0, color)
func set_output_color(color: Color) -> void:
set_slot_color_right(1 if horizontal else 2, color)
func _on_size_changed():
add_theme_constant_override(
"port_offset", 12 * BeehaveUtils.get_editor_scale() if horizontal else round(size.x / 2.0)
)

Some files were not shown because too many files have changed in this diff Show More