diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8ad74f7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/.gitignore b/.gitignore index bf83296..6ab985d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ export_presets.cfg data_*/ mono_crash.*.json +/android/ diff --git a/TerrainGen.gd b/TerrainGen.gd new file mode 100644 index 0000000..c7a84ca --- /dev/null +++ b/TerrainGen.gd @@ -0,0 +1,37 @@ +@tool +extends GridMap +class_name TerrainGen + +signal map_changed() + +@export var region: Rect2i = Rect2i(0,0,200,200): + set(value): + region = value + generate() +@export var noise: Noise: + set(value): + noise = value + generate() +@export var max_height: int = 10: + set(value): + max_height = value + generate() + +func _ready() -> void: + generate() + +func generate() -> void: + clear() + if noise == null: + return + for x in range(region.position.x, region.size.x): + for y in range(region.position.y, region.size.y): + var point: Vector2i = Vector2i(x,y) + var noise_point: Vector2 = Vector2(point) + + var val: float = noise.get_noise_2d(noise_point.x, noise_point.y) + var height: int = floori(((val + 1)/2.0) * max_height) + + var point_3d: Vector3i = Vector3i(point.x, height, point.y) + set_cell_item(point_3d, 0) + map_changed.emit() diff --git a/TerrainGen.gd.uid b/TerrainGen.gd.uid new file mode 100644 index 0000000..eb5dbdb --- /dev/null +++ b/TerrainGen.gd.uid @@ -0,0 +1 @@ +uid://b7hc3l8i50646 diff --git a/addons/LICENSE b/addons/LICENSE new file mode 100644 index 0000000..2089d5d --- /dev/null +++ b/addons/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 iiMidknightii + +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. diff --git a/addons/PathMesh3D/bin/libpath_mesh_3d.linux.template_debug.x86_64.so b/addons/PathMesh3D/bin/libpath_mesh_3d.linux.template_debug.x86_64.so new file mode 100644 index 0000000..7243ed5 Binary files /dev/null and b/addons/PathMesh3D/bin/libpath_mesh_3d.linux.template_debug.x86_64.so differ diff --git a/addons/PathMesh3D/bin/libpath_mesh_3d.linux.template_release.x86_64.so b/addons/PathMesh3D/bin/libpath_mesh_3d.linux.template_release.x86_64.so new file mode 100644 index 0000000..50b11ff Binary files /dev/null and b/addons/PathMesh3D/bin/libpath_mesh_3d.linux.template_release.x86_64.so differ diff --git a/addons/PathMesh3D/bin/path_mesh_3d.windows.template_debug.x86_64.dll b/addons/PathMesh3D/bin/path_mesh_3d.windows.template_debug.x86_64.dll new file mode 100644 index 0000000..d3ad5a0 Binary files /dev/null and b/addons/PathMesh3D/bin/path_mesh_3d.windows.template_debug.x86_64.dll differ diff --git a/addons/PathMesh3D/bin/path_mesh_3d.windows.template_debug.x86_64.exp b/addons/PathMesh3D/bin/path_mesh_3d.windows.template_debug.x86_64.exp new file mode 100644 index 0000000..be3492b Binary files /dev/null and b/addons/PathMesh3D/bin/path_mesh_3d.windows.template_debug.x86_64.exp differ diff --git a/addons/PathMesh3D/bin/path_mesh_3d.windows.template_debug.x86_64.lib b/addons/PathMesh3D/bin/path_mesh_3d.windows.template_debug.x86_64.lib new file mode 100644 index 0000000..8963981 Binary files /dev/null and b/addons/PathMesh3D/bin/path_mesh_3d.windows.template_debug.x86_64.lib differ diff --git a/addons/PathMesh3D/bin/path_mesh_3d.windows.template_release.x86_64.dll b/addons/PathMesh3D/bin/path_mesh_3d.windows.template_release.x86_64.dll new file mode 100644 index 0000000..6b41c11 Binary files /dev/null and b/addons/PathMesh3D/bin/path_mesh_3d.windows.template_release.x86_64.dll differ diff --git a/addons/PathMesh3D/bin/path_mesh_3d.windows.template_release.x86_64.exp b/addons/PathMesh3D/bin/path_mesh_3d.windows.template_release.x86_64.exp new file mode 100644 index 0000000..a3b3ebd Binary files /dev/null and b/addons/PathMesh3D/bin/path_mesh_3d.windows.template_release.x86_64.exp differ diff --git a/addons/PathMesh3D/bin/path_mesh_3d.windows.template_release.x86_64.lib b/addons/PathMesh3D/bin/path_mesh_3d.windows.template_release.x86_64.lib new file mode 100644 index 0000000..f90f1e6 Binary files /dev/null and b/addons/PathMesh3D/bin/path_mesh_3d.windows.template_release.x86_64.lib differ diff --git a/addons/PathMesh3D/icons/PathExtrude3D.svg b/addons/PathMesh3D/icons/PathExtrude3D.svg new file mode 100644 index 0000000..f4026de --- /dev/null +++ b/addons/PathMesh3D/icons/PathExtrude3D.svg @@ -0,0 +1,350 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/PathMesh3D/icons/PathExtrude3D.svg.import b/addons/PathMesh3D/icons/PathExtrude3D.svg.import new file mode 100644 index 0000000..e58394c --- /dev/null +++ b/addons/PathMesh3D/icons/PathExtrude3D.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://8eb8hcla5i0u" +path="res://.godot/imported/PathExtrude3D.svg-d52ee0a8b6d6a0e2a8770d6722511a3d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/PathMesh3D/icons/PathExtrude3D.svg" +dest_files=["res://.godot/imported/PathExtrude3D.svg-d52ee0a8b6d6a0e2a8770d6722511a3d.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=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/PathMesh3D/icons/PathMesh3D.svg b/addons/PathMesh3D/icons/PathMesh3D.svg new file mode 100644 index 0000000..feef06d --- /dev/null +++ b/addons/PathMesh3D/icons/PathMesh3D.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + diff --git a/addons/PathMesh3D/icons/PathMesh3D.svg.import b/addons/PathMesh3D/icons/PathMesh3D.svg.import new file mode 100644 index 0000000..3ce14b7 --- /dev/null +++ b/addons/PathMesh3D/icons/PathMesh3D.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bh5p7hkaa8hie" +path="res://.godot/imported/PathMesh3D.svg-eb764ef0d374aa9048b4a6fb2fc562f4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/PathMesh3D/icons/PathMesh3D.svg" +dest_files=["res://.godot/imported/PathMesh3D.svg-eb764ef0d374aa9048b4a6fb2fc562f4.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=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/PathMesh3D/icons/PathMesh3DIcon.png b/addons/PathMesh3D/icons/PathMesh3DIcon.png new file mode 100644 index 0000000..9684850 Binary files /dev/null and b/addons/PathMesh3D/icons/PathMesh3DIcon.png differ diff --git a/addons/PathMesh3D/icons/PathMesh3DIcon.png.import b/addons/PathMesh3D/icons/PathMesh3DIcon.png.import new file mode 100644 index 0000000..289e94d --- /dev/null +++ b/addons/PathMesh3D/icons/PathMesh3DIcon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b6nqpkc7x77ix" +path="res://.godot/imported/PathMesh3DIcon.png-04c24475cefba24f106467cd168d7ccf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/PathMesh3D/icons/PathMesh3DIcon.png" +dest_files=["res://.godot/imported/PathMesh3DIcon.png-04c24475cefba24f106467cd168d7ccf.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 diff --git a/addons/PathMesh3D/icons/PathMesh3DIcon.svg b/addons/PathMesh3D/icons/PathMesh3DIcon.svg new file mode 100644 index 0000000..745aa23 --- /dev/null +++ b/addons/PathMesh3D/icons/PathMesh3DIcon.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + diff --git a/addons/PathMesh3D/icons/PathMesh3DIcon.svg.import b/addons/PathMesh3D/icons/PathMesh3DIcon.svg.import new file mode 100644 index 0000000..4c57340 --- /dev/null +++ b/addons/PathMesh3D/icons/PathMesh3DIcon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c77khe5dqwb3h" +path="res://.godot/imported/PathMesh3DIcon.svg-4d77d3947e234f16cb0dade5ee147492.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/PathMesh3D/icons/PathMesh3DIcon.svg" +dest_files=["res://.godot/imported/PathMesh3DIcon.svg-4d77d3947e234f16cb0dade5ee147492.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=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/PathMesh3D/icons/PathMultiMesh3D.svg b/addons/PathMesh3D/icons/PathMultiMesh3D.svg new file mode 100644 index 0000000..a12171c --- /dev/null +++ b/addons/PathMesh3D/icons/PathMultiMesh3D.svg @@ -0,0 +1,414 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/PathMesh3D/icons/PathMultiMesh3D.svg.import b/addons/PathMesh3D/icons/PathMultiMesh3D.svg.import new file mode 100644 index 0000000..4a9e69e --- /dev/null +++ b/addons/PathMesh3D/icons/PathMultiMesh3D.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cffxlnw1viopm" +path="res://.godot/imported/PathMultiMesh3D.svg-f1401263c315f0db21ed219e14790414.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/PathMesh3D/icons/PathMultiMesh3D.svg" +dest_files=["res://.godot/imported/PathMultiMesh3D.svg-f1401263c315f0db21ed219e14790414.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=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/PathMesh3D/icons/PathScene3D.svg b/addons/PathMesh3D/icons/PathScene3D.svg new file mode 100644 index 0000000..c89706e --- /dev/null +++ b/addons/PathMesh3D/icons/PathScene3D.svg @@ -0,0 +1,58 @@ + + + + + + + + + diff --git a/addons/PathMesh3D/icons/PathScene3D.svg.import b/addons/PathMesh3D/icons/PathScene3D.svg.import new file mode 100644 index 0000000..a14b9cf --- /dev/null +++ b/addons/PathMesh3D/icons/PathScene3D.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://chm4bonb3hjnw" +path="res://.godot/imported/PathScene3D.svg-d846d90d01178706737043a57e46dba1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/PathMesh3D/icons/PathScene3D.svg" +dest_files=["res://.godot/imported/PathScene3D.svg-d846d90d01178706737043a57e46dba1.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=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/PathMesh3D/path_mesh_3d.gdextension b/addons/PathMesh3D/path_mesh_3d.gdextension new file mode 100644 index 0000000..7c2c540 --- /dev/null +++ b/addons/PathMesh3D/path_mesh_3d.gdextension @@ -0,0 +1,40 @@ +[configuration] + +entry_symbol = "path_mesh_3d_init" +compatibility_minimum = "4.3" +reloadable = true + +[libraries] + +macos.debug = "res://addons/PathMesh3D/bin/path_mesh_3d.macos.template_debug.framework" +macos.release = "res://addons/PathMesh3D/bin/path_mesh_3d.macos.template_release.framework" +ios.debug = "res://addons/PathMesh3D/bin/path_mesh_3d.ios.template_debug.xcframework" +ios.release = "res://addons/PathMesh3D/bin/path_mesh_3d.ios.template_release.xcframework" +windows.debug.x86_32 = "res://addons/PathMesh3D/bin/path_mesh_3d.windows.template_debug.x86_32.dll" +windows.release.x86_32 = "res://addons/PathMesh3D/bin/path_mesh_3d.windows.template_release.x86_32.dll" +windows.debug.x86_64 = "res://addons/PathMesh3D/bin/path_mesh_3d.windows.template_debug.x86_64.dll" +windows.release.x86_64 = "res://addons/PathMesh3D/bin/path_mesh_3d.windows.template_release.x86_64.dll" +linux.debug.x86_64 = "res://addons/PathMesh3D/bin/libpath_mesh_3d.linux.template_debug.x86_64.so" +linux.release.x86_64 = "res://addons/PathMesh3D/bin/libpath_mesh_3d.linux.template_release.x86_64.so" +linux.debug.arm64 = "res://addons/PathMesh3D/bin/libpath_mesh_3d.linux.template_debug.arm64.so" +linux.release.arm64 = "res://addons/PathMesh3D/bin/libpath_mesh_3d.linux.template_release.arm64.so" +linux.debug.rv64 = "res://addons/PathMesh3D/bin/libpath_mesh_3d.linux.template_debug.rv64.so" +linux.release.rv64 = "res://addons/PathMesh3D/bin/libpath_mesh_3d.linux.template_release.rv64.so" +android.debug.x86_64 = "res://addons/PathMesh3D/bin/path_mesh_3d.android.template_debug.x86_64.so" +android.release.x86_64 = "res://addons/PathMesh3D/bin/path_mesh_3d.android.template_release.x86_64.so" +android.debug.arm64 = "res://addons/PathMesh3D/bin/path_mesh_3d.android.template_debug.arm64.so" +android.release.arm64 = "res://addons/PathMesh3D/bin/path_mesh_3d.android.template_release.arm64.so" + +[dependencies] +ios.debug = { + "res://addons/PathMesh3D/bin/libgodot-cpp.ios.template_debug.xcframework": "" +} +ios.release = { + "res://addons/PathMesh3D/bin/libgodot-cpp.ios.template_release.xcframework": "" +} + +[icons] +PathMesh3D = "res://addons/PathMesh3D/icons/PathMesh3D.svg" +PathExtrude3D = "res://addons/PathMesh3D/icons/PathExtrude3D.svg" +PathMultiMesh3D = "res://addons/PathMesh3D/icons/PathMultiMesh3D.svg" +PathScene3D = "res://addons/PathMesh3D/icons/PathScene3D.svg" \ No newline at end of file diff --git a/addons/PathMesh3D/path_mesh_3d.gdextension.uid b/addons/PathMesh3D/path_mesh_3d.gdextension.uid new file mode 100644 index 0000000..4e20b25 --- /dev/null +++ b/addons/PathMesh3D/path_mesh_3d.gdextension.uid @@ -0,0 +1 @@ +uid://csxxhm0kw76kb diff --git a/addons/PathMesh3D/plugin.cfg b/addons/PathMesh3D/plugin.cfg new file mode 100644 index 0000000..20270b4 --- /dev/null +++ b/addons/PathMesh3D/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="PathMesh3D" +description="A fast set of 3D mesh extrusion and tiling nodes implemented as a C++ GDExtension." +author="iiMidknightii" +version="1.3.0" +script="plugin.gd" diff --git a/addons/PathMesh3D/plugin.gd b/addons/PathMesh3D/plugin.gd new file mode 100644 index 0000000..502e379 --- /dev/null +++ b/addons/PathMesh3D/plugin.gd @@ -0,0 +1,53 @@ +@tool +extends EditorPlugin + +const PathMesh3DOptions := preload("res://addons/PathMesh3D/scripts/path_mesh_3d_options.gd") +const PathMesh3DOptionsScene := preload("res://addons/PathMesh3D/scenes/path_mesh_3d_options.tscn") + +const PathScene3DOptions := preload("res://addons/PathMesh3D/scripts/path_scene_3d_options.gd") +const PathScene3DOptionsScene := preload("res://addons/PathMesh3D/scenes/path_scene_3d_options.tscn") + +var _mesh_editor_button: PathMesh3DOptions +var _scene_editor_button: PathScene3DOptions + +var _path_object + +func _enter_tree() -> void: + _mesh_editor_button = PathMesh3DOptionsScene.instantiate() + add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, _mesh_editor_button) + _mesh_editor_button.hide() + + _scene_editor_button = PathScene3DOptionsScene.instantiate() + add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, _scene_editor_button) + _scene_editor_button.hide() + +func _exit_tree() -> void: + remove_control_from_container(CONTAINER_SPATIAL_EDITOR_MENU, _mesh_editor_button) + remove_control_from_container(CONTAINER_SPATIAL_EDITOR_MENU, _scene_editor_button) + _mesh_editor_button.queue_free() + _scene_editor_button.queue_free() + + +func _handles(object: Object) -> bool: + return object is PathMesh3D or object is PathExtrude3D or object is PathScene3D + + +func _edit(object: Object) -> void: + if object is PathMesh3D or object is PathExtrude3D and _mesh_editor_button: + _path_object = object + _mesh_editor_button.path_mesh = object + _mesh_editor_button.ur = get_undo_redo() + elif object is PathScene3D and _scene_editor_button: + _path_object = object + _scene_editor_button.path_scene = object + _scene_editor_button.ur = get_undo_redo() + + +func _make_visible(visible: bool) -> void: + if _path_object is PathMesh3D or _path_object is PathExtrude3D and visible: + _mesh_editor_button.visible = visible + elif _path_object is PathScene3D and visible: + _scene_editor_button.visible = visible + elif not visible: + _mesh_editor_button.visible = visible + _scene_editor_button.visible = visible diff --git a/addons/PathMesh3D/plugin.gd.uid b/addons/PathMesh3D/plugin.gd.uid new file mode 100644 index 0000000..3dc57b7 --- /dev/null +++ b/addons/PathMesh3D/plugin.gd.uid @@ -0,0 +1 @@ +uid://ba3eavswdmx3m diff --git a/addons/PathMesh3D/scenes/path_mesh_3d_options.tscn b/addons/PathMesh3D/scenes/path_mesh_3d_options.tscn new file mode 100644 index 0000000..5769a18 --- /dev/null +++ b/addons/PathMesh3D/scenes/path_mesh_3d_options.tscn @@ -0,0 +1,83 @@ +[gd_scene load_steps=3 format=3 uid="uid://bf6p2xos0dryr"] + +[ext_resource type="Script" uid="uid://k16bgqnrauft" path="res://addons/PathMesh3D/scripts/path_mesh_3d_options.gd" id="1_ljqft"] +[ext_resource type="Texture2D" uid="uid://bh5p7hkaa8hie" path="res://addons/PathMesh3D/icons/PathMesh3D.svg" id="1_sjiwc"] + +[node name="MenuButton" type="MenuButton"] +offset_right = 155.0 +offset_bottom = 146.0 +text = "PathMesh3D" +icon = ExtResource("1_sjiwc") +switch_on_hover = true +item_count = 2 +popup/item_0/text = "Bake Extruded Mesh" +popup/item_0/id = 1 +popup/item_1/text = "Create Collision Shape..." +popup/item_1/id = 1 +script = ExtResource("1_ljqft") + +[node name="CollisionDialog" type="ConfirmationDialog" parent="."] +title = "Create Collision Shape" +size = Vector2i(220, 177) +ok_button_text = "Create" + +[node name="VBoxContainer" type="VBoxContainer" parent="CollisionDialog"] +offset_left = 8.0 +offset_top = 8.0 +offset_right = 212.0 +offset_bottom = 128.0 + +[node name="Label" type="Label" parent="CollisionDialog/VBoxContainer"] +layout_mode = 2 +text = "Collision Shape Placement" + +[node name="OptionButton" type="OptionButton" parent="CollisionDialog/VBoxContainer"] +layout_mode = 2 +selected = 0 +item_count = 2 +popup/item_0/text = "Sibling" +popup/item_1/text = "Static Body Child" +popup/item_1/id = 1 + +[node name="Label2" type="Label" parent="CollisionDialog/VBoxContainer"] +layout_mode = 2 +text = "Collision Shape Type" + +[node name="OptionButton2" type="OptionButton" parent="CollisionDialog/VBoxContainer"] +layout_mode = 2 +selected = 0 +item_count = 4 +popup/item_0/text = "Trimesh" +popup/item_1/text = "Single Convex" +popup/item_1/id = 1 +popup/item_2/text = "Simplified Convex" +popup/item_2/id = 2 +popup/item_3/text = "Multiple Convex" +popup/item_3/id = 3 +popup/item_3/disabled = true + +[node name="BakeDialog" type="ConfirmationDialog" parent="."] +title = "Bake Extruded Mesh" +position = Vector2i(0, 36) +size = Vector2i(200, 115) +ok_button_text = "Bake" + +[node name="VBoxContainer" type="VBoxContainer" parent="BakeDialog"] +offset_left = 8.0 +offset_top = 8.0 +offset_right = 192.0 +offset_bottom = 66.0 + +[node name="Label" type="Label" parent="BakeDialog/VBoxContainer"] +layout_mode = 2 +text = "Baked Mesh Placement" + +[node name="OptionButton" type="OptionButton" parent="BakeDialog/VBoxContainer"] +layout_mode = 2 +selected = 0 +item_count = 2 +popup/item_0/text = "Sibling" +popup/item_1/text = "Child" +popup/item_1/id = 1 + +[node name="ErrDialog" type="AcceptDialog" parent="."] diff --git a/addons/PathMesh3D/scenes/path_scene_3d_options.tscn b/addons/PathMesh3D/scenes/path_scene_3d_options.tscn new file mode 100644 index 0000000..e38779f --- /dev/null +++ b/addons/PathMesh3D/scenes/path_scene_3d_options.tscn @@ -0,0 +1,43 @@ +[gd_scene load_steps=3 format=3 uid="uid://ti68eqdjrepf"] + +[ext_resource type="Texture2D" uid="uid://chm4bonb3hjnw" path="res://addons/PathMesh3D/icons/PathScene3D.svg" id="1_gjelh"] +[ext_resource type="Script" uid="uid://cwc5u78hgi17j" path="res://addons/PathMesh3D/scripts/path_scene_3d_options.gd" id="2_jba24"] + +[node name="MenuButton" type="MenuButton"] +offset_right = 155.0 +offset_bottom = 146.0 +text = "PathScene3D" +icon = ExtResource("1_gjelh") +switch_on_hover = true +item_count = 1 +popup/item_0/text = "Bake Instances" +popup/item_0/id = 1 +script = ExtResource("2_jba24") + +[node name="BakeDialog" type="ConfirmationDialog" parent="."] +auto_translate_mode = 1 +title = "Bake Instanced Scenes" +position = Vector2i(0, 36) +size = Vector2i(228, 115) +ok_button_text = "Bake" + +[node name="VBoxContainer" type="VBoxContainer" parent="BakeDialog"] +offset_left = 8.0 +offset_top = 8.0 +offset_right = 220.0 +offset_bottom = 66.0 + +[node name="Label" type="Label" parent="BakeDialog/VBoxContainer"] +layout_mode = 2 +text = "Baked Instance Placement" + +[node name="OptionButton" type="OptionButton" parent="BakeDialog/VBoxContainer"] +layout_mode = 2 +selected = 0 +item_count = 2 +popup/item_0/text = "Sibling" +popup/item_1/text = "Child" +popup/item_1/id = 1 + +[node name="ErrDialog" type="AcceptDialog" parent="."] +auto_translate_mode = 1 diff --git a/addons/PathMesh3D/scripts/path_mesh_3d_options.gd b/addons/PathMesh3D/scripts/path_mesh_3d_options.gd new file mode 100644 index 0000000..1acbd5f --- /dev/null +++ b/addons/PathMesh3D/scripts/path_mesh_3d_options.gd @@ -0,0 +1,145 @@ +@tool +extends MenuButton + +enum Operation {BAKE, COLLISION} +enum Shape {TRIMESH, SINGLE_CONVEX, SIMPLE_CONVEX, MULTIPLE_CONVEX} +enum Placement {SIBLING, CHILD} + +var path_mesh: Node +var ur: EditorUndoRedoManager + +@onready var _err_dialog: AcceptDialog = $ErrDialog +@onready var _collision_dialog: ConfirmationDialog = $CollisionDialog +@onready var _shape_placement: OptionButton = $CollisionDialog/VBoxContainer/OptionButton +@onready var _shape_type: OptionButton = $CollisionDialog/VBoxContainer/OptionButton2 +@onready var _bake_dialog: ConfirmationDialog = $BakeDialog +@onready var _bake_placement: OptionButton = $BakeDialog/VBoxContainer/OptionButton + +func _ready() -> void: + get_popup().index_pressed.connect(_on_menu_pressed) + _bake_dialog.confirmed.connect(_on_bake_confirmed) + _collision_dialog.confirmed.connect(_on_collision_shape_confirmed) + + +func _on_menu_pressed(id: int) -> void: + match id: + Operation.BAKE: + _bake_dialog.popup_centered() + Operation.COLLISION: + _collision_dialog.popup_centered() + + +func _on_bake_confirmed() -> void: + if not (path_mesh is PathMesh3D or path_mesh is PathExtrude3D): + return + + if not ur: + return + + var placement := _bake_placement.selected + var p_owner := EditorInterface.get_edited_scene_root() + if p_owner == path_mesh and placement == Placement.SIBLING: + _err_dialog.dialog_text = "Can't add Mesh Instance as sibling of scene root." + _err_dialog.popup_centered() + return + + var mesh: Mesh = path_mesh.get_baked_mesh() + if mesh == null: + _err_dialog.dialog_text = "No mesh to create Instance from." + _err_dialog.popup_centered() + return + + var minstance := MeshInstance3D.new() + minstance.mesh = mesh + minstance.name = "MeshInstance3D" + + if placement == Placement.SIBLING: + ur.add_do_method(path_mesh, "add_sibling", minstance, true) + ur.add_do_method(minstance, "set_owner", p_owner) + ur.add_do_reference(minstance) + ur.add_undo_method(path_mesh.get_parent(), "remove_child", minstance) + else: + ur.add_do_method(path_mesh, "add_child", minstance, true) + ur.add_do_method(minstance, "set_owner", p_owner) + ur.add_do_reference(minstance) + ur.add_undo_method(path_mesh, "remove_child", minstance) + + ur.commit_action() + + +func _on_collision_shape_confirmed() -> void: + if not (path_mesh is PathMesh3D or path_mesh is PathExtrude3D): + return + + if not ur: + return + + var mesh: Mesh = path_mesh.get_baked_mesh() + if mesh == null: + _err_dialog.dialog_text = "No mesh to create Collision Shape from." + _err_dialog.popup_centered() + return + + var placement := _shape_placement.selected + var shape_type := _shape_type.selected + + var str := "Collision Shape Sibling" if placement == Placement.SIBLING else "Static Body" + + match shape_type: + Shape.TRIMESH: ur.create_action("Create Trimesh " + str) + Shape.SINGLE_CONVEX: ur.create_action("Create Single Convex " + str) + Shape.SIMPLE_CONVEX: ur.create_action("Create Simplified Convex "+ str) + Shape.MULTIPLE_CONVEX: ur.create_action("Create Multiple Convex " + str) + _: return + + if EditorInterface.get_edited_scene_root() == path_mesh and placement == 0: + _err_dialog.dialog_text = "Can't create a collision shape as sibling for the scene root." + _err_dialog.popup_centered() + return + + var scene_owner := EditorInterface.get_edited_scene_root() + var shapes: Array[Shape3D] = [] + match shape_type: + Shape.TRIMESH: + shapes.push_back(mesh.create_trimesh_shape()) + Shape.SINGLE_CONVEX: + shapes.push_back(mesh.create_convex_shape(true, false)) + Shape.SIMPLE_CONVEX: + shapes.push_back(mesh.create_convex_shape(true, true)) + Shape.MULTIPLE_CONVEX: + var settings := MeshConvexDecompositionSettings.new() + settings.max_convex_hulls = 32 + settings.max_concavity = 0.001 + shapes = mesh.convex_decompose(settings) + + if shapes.is_empty(): + _err_dialog.dialog_text = "Cannot create collision shape." + _err_dialog.popup_centered() + return + + var p_owner := EditorInterface.get_edited_scene_root() + if placement == Placement.CHILD: + var body := StaticBody3D.new() + ur.add_do_method(path_mesh, "add_child", body, true) + ur.add_do_method(body, "set_owner", p_owner) + + for shape: Shape3D in shapes: + var cshape := CollisionShape3D.new() + cshape.shape = shape + ur.add_do_method(body, "add_child", cshape, true) + ur.add_do_method(cshape, "set_owner", p_owner) + + ur.add_do_reference(body) + ur.add_undo_method(path_mesh, "remove_child", body) + else: + for shape: Shape3D in shapes: + var cshape := CollisionShape3D.new() + cshape.shape = shape + cshape.name = "CollisionShape3D" + cshape.transform = path_mesh.transform + ur.add_do_method(path_mesh, "add_sibling", cshape, true) + ur.add_do_method(cshape, "set_owner", p_owner) + ur.add_do_reference(cshape) + ur.add_undo_method(path_mesh.get_parent(), "remove_child", cshape) + + ur.commit_action() diff --git a/addons/PathMesh3D/scripts/path_mesh_3d_options.gd.uid b/addons/PathMesh3D/scripts/path_mesh_3d_options.gd.uid new file mode 100644 index 0000000..5bbd80e --- /dev/null +++ b/addons/PathMesh3D/scripts/path_mesh_3d_options.gd.uid @@ -0,0 +1 @@ +uid://k16bgqnrauft diff --git a/addons/PathMesh3D/scripts/path_scene_3d_options.gd b/addons/PathMesh3D/scripts/path_scene_3d_options.gd new file mode 100644 index 0000000..f1dbc5a --- /dev/null +++ b/addons/PathMesh3D/scripts/path_scene_3d_options.gd @@ -0,0 +1,54 @@ +@tool +extends MenuButton + +enum Operation {BAKE} +enum Placement {SIBLING, CHILD} + +var path_scene: Node +var ur: EditorUndoRedoManager + +@onready var _err_dialog: AcceptDialog = $ErrDialog +@onready var _bake_dialog: ConfirmationDialog = $BakeDialog +@onready var _bake_placement: OptionButton = $BakeDialog/VBoxContainer/OptionButton + +func _ready() -> void: + get_popup().index_pressed.connect(_on_menu_pressed) + _bake_dialog.confirmed.connect(_on_bake_confirmed) + + +func _on_menu_pressed(id: int) -> void: + match id: + Operation.BAKE: + _bake_dialog.popup_centered() + + +func _on_bake_confirmed() -> void: + if not (path_scene is PathScene3D): + return + + if not ur: + return + + var placement := _bake_placement.selected + var p_owner := EditorInterface.get_edited_scene_root() + if p_owner == path_scene and placement == Placement.SIBLING: + _err_dialog.dialog_text = "Can't add instances as siblings of scene root." + _err_dialog.popup_centered() + return + + var instances: Array[Node3D] = path_scene.bake_instances() + + for i: Node3D in instances: + if placement == Placement.SIBLING: + ur.add_do_method(path_scene, "add_sibling", i, true) + ur.add_do_method(i, "set_owner", p_owner) + ur.add_do_reference(i) + ur.add_undo_method(path_scene.get_parent(), "remove_child", i) + else: + + ur.add_do_method(path_scene, "add_child", i, true) + ur.add_do_method(i, "set_owner", p_owner) + ur.add_do_reference(i) + ur.add_undo_method(path_scene, "remove_child", i) + + ur.commit_action() diff --git a/addons/PathMesh3D/scripts/path_scene_3d_options.gd.uid b/addons/PathMesh3D/scripts/path_scene_3d_options.gd.uid new file mode 100644 index 0000000..7373640 --- /dev/null +++ b/addons/PathMesh3D/scripts/path_scene_3d_options.gd.uid @@ -0,0 +1 @@ +uid://cwc5u78hgi17j diff --git a/addons/README.md b/addons/README.md new file mode 100644 index 0000000..a9d7cfb --- /dev/null +++ b/addons/README.md @@ -0,0 +1,44 @@ +# ![](addons/PathMesh3D/icons/PathMesh3DIcon.png) PathMesh3D + A set of simple Godot 3D nodes for extruding and instancing 3D meshes along a Path3D. Implemented as a GDExtension in C++ for speed. + +## Installation +### From Godot Asset Library in the Editor +Click the `AssetLib` button at the top of the Godot editor and search for `PathMesh3D`. When prompted where to install it, you can select only the folder named "addons". If you wish to modify or recompile the addon, then you'll need to include the "godot-cpp" and "src" folders along with the "SConstruct" file from this repository. + + ### From Godot Asset Library Web + Head over to [the PathMesh3D page on the asset library website](https://godotengine.org/asset-library/asset) and click the download button. Unzip the download into a location of your choosing. To put the addon in your project, just copy the "addons" folder into the project directory. + + ### From GitHub.com + You can download the full repository for PathMesh3D [here](https://github.com/iiMidknightii/PathMesh3D). You can clone this repository by doing `git clone https://github.com/iiMidknightii/PathMesh3D.git` in the directory of your choosing. If you want to compile your own binaries this is the best option. To put the addon in your project, just copy the "addons" folder into the project directory. + +## Tutorial +> [!NOTE] +> `PathMesh3D` and `PathExtrude3D` both have a plugin button to generate baked meshes and collision shapes. In the editor, you can enable this button by enabling the `PathMesh3D` plugin. + +### PathMesh3D +`PathMesh3D` is a great node if you want to take a 3D model and "tile" or "repeat" it along a `Path3D` node within your scene. The `Mesh` model provided will be duplicated along its Z axis according to the settings chosen for each surface. Since each surface has its own independent settings, there is a high degree of customization available. + +Simply add the `PathMesh3D` node to the scene, set its `path_3d` property to a `Path3D` node, and set its `mesh` property to any `Mesh` derived resource. From there, you can tweak the settings for each surface to get your desired effect. If you want to create a permanent, separate node as a "snapshot" of the extruded mesh, hit the `PathMesh3D` button on the editor toolbar and select "Bake Mesh". You can also create collision shapes and static bodies similarly to `MeshInstance3D` with that same button. + +![](screenshots/PathMesh3D.png) + +### PathExtrude3D +`PathExtrude3D` works similarly to the `CSGPolygon` node when in path mode. First, you define the cross section using the `profile` property. This property uses any one of the `PathExtrudeProfileBase` classes, including rectangular, circular, etc. You can also create your own profile by creating a custom script inheriting from `PathExtrudeProfileBase` and overriding the virtual `_generate_cross_section` method. This resource stores the cross section vertices in arrays similar to `ArrayMesh` that will be used by the `PathExtrude3D`. Next, set the `path_3d` property to any `Path3D` node in the scene. From there, the cross section will be extruded according to the settings you have chosen. + +![](screenshots/PathExtrude3D.png) + +### PathMultiMesh3D +`PathMultiMesh3D` works similarly to `PathMesh3D`, but instead of creating one combined mesh, it generates the instances of a `MultiMesh` resource along the path. Just set the `mesh` property to a `MultiMesh` (and select a base mesh for it). Then, set the `path_3d` property to a `Path3D` node in the scene. The node will automatically set the `MultiMesh` `instance_count` property and distribute their transforms along the path according to the selected settings. + +![](screenshots/PathMultiMesh3D.png) + +### PathScene3D +`PathScene3D` creates instances of a `PackedScene` resource along the the path. It will automatically add the instances as internal children of itself and distribute their transforms according to selected settings. If it is desired, the instances can be "baked" by calling `bake_instances`, which unparents them from the `PathScene3D` node and returns them in an array. From there, they can be reparented as more permanent nodes. + +## Latest Release - v1.3.0 +* Fixed `PathExtrude3D` UV generation and material issues. +* Added the `PathScene3D` node. +* Applied the `Path3D` node transform to the generated meshes/instances, while un-applying the helper node's transform (meaning the mesh/instance will always follow the curve in the editor no matter the relative node transformations). + +## Contributing +Feel free to leave any feedback, suggestions, bug reports, and contributions to the repository at [https://github.com/iiMidknightii/PathMesh3D](https://github.com/iiMidknightii/PathMesh3D). diff --git a/addons/debug_draw_3d/LICENSE b/addons/debug_draw_3d/LICENSE new file mode 100644 index 0000000..617a15b --- /dev/null +++ b/addons/debug_draw_3d/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 DmitriySalnikov + +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, andor 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. \ No newline at end of file diff --git a/addons/debug_draw_3d/README.md b/addons/debug_draw_3d/README.md new file mode 100644 index 0000000..7eb72aa --- /dev/null +++ b/addons/debug_draw_3d/README.md @@ -0,0 +1,158 @@ +![icon](/images/icon_3d_128.png) + +# Debug drawing utility for Godot + +This is an add-on for debug drawing in 3D and for some 2D overlays, which is written in `C++` and can be used with `GDScript` or `C#`. + +Based on my previous addon, which was developed [only for C#](https://github.com/DmitriySalnikov/godot_debug_draw_cs), and which was inspired by [Zylann's GDScript addon](https://github.com/Zylann/godot_debug_draw) + +## [Documentation](https://dd3d.dmitriysalnikov.ru/docs/) + +## [Godot 3 version](https://github.com/DmitriySalnikov/godot_debug_draw_3d/tree/godot_3) + +## Support me + +Your support adds motivation to develop my public projects. + +Boosty + +USDT-TRC20 + +USDT-TRC20 TEw934PrsffHsAn5M63SoHYRuZo984EF6v + +## Features + +3D: + +* Arrow +* Billboard opaque square +* Box +* Camera Frustum +* Cylinder +* Gizmo +* Grid +* Line +* Line Path +* Line with Arrow +* Plane +* Points +* Position 3D (3 crossing axes) +* Sphere + +2D: + +* **[Work in progress]** + +Overlay: + +* Text (with grouping and coloring) +* FPS Graph +* Custom Graphs + +Precompiled for: + +* Windows +* Linux (built on Ubuntu 22.04) +* macOS (10.15+) +* Android (5.0+) +* iOS +* Web (Firefox is supported by Godot 4.3+) + +This addon supports working with several World3D and different Viewports. +There is also a no depth test mode and other settings that can be changed for each instance. + +This library supports double-precision builds, for more information, [see the documentation](https://dd3d.dmitriysalnikov.ru/docs/?page=md_docs_2DoublePrecision.html). + +## [Interactive Web Demo](https://dd3d.dmitriysalnikov.ru/demo/) + +[![screenshot_web](/images/screenshot_web.png)](https://dd3d.dmitriysalnikov.ru/demo/) + +## Download + +To download, use the [Godot Asset Library](https://godotengine.org/asset-library/asset/1766) or use one of the stable versions from the [GitHub Releases](https://github.com/DmitriySalnikov/godot_debug_draw_3d/releases) page. + +For versions prior to `1.4.5`, just download one of the `source codes` in the assets. For newer versions, download `debug-draw-3d_[version].zip`. + +### Installation + +* Close editor +* Copy `addons/debug_draw_3d` to your `addons` folder, create it if the folder doesn't exist +* Launch editor + +## Examples + +More examples can be found in the `examples_dd3d/` folder. + +Simple test: + +```gdscript +func _process(delta: float) -> void: + var _time = Time.get_ticks_msec() / 1000.0 + var box_pos = Vector3(0, sin(_time * 4), 0) + var line_begin = Vector3(-1, sin(_time * 4), 0) + var line_end = Vector3(1, cos(_time * 4), 0) + + DebugDraw3D.draw_box(box_pos, Quaternion.IDENTITY, Vector3(1, 2, 1), Color(0, 1, 0)) + DebugDraw3D.draw_line(line_begin, line_end, Color(1, 1, 0)) + DebugDraw2D.set_text("Time", _time) + DebugDraw2D.set_text("Frames drawn", Engine.get_frames_drawn()) + DebugDraw2D.set_text("FPS", Engine.get_frames_per_second()) + DebugDraw2D.set_text("delta", delta) +``` + +![screenshot_1](/images/screenshot_1.png) + +An example of using scoped configs: + +```gdscript +@tool +extends Node3D + +func _ready(): + # Set the base scoped_config. + # Each frame will be reset to these scoped values. + DebugDraw3D.scoped_config().set_thickness(0.1).set_center_brightness(0.6) + +func _process(delta): + # Draw using the base scoped config. + DebugDraw3D.draw_box(Vector3.ZERO, Quaternion.IDENTITY, Vector3.ONE * 2, Color.CORNFLOWER_BLUE) + if true: + # Create a scoped config that will exist until exiting this if. + var _s = DebugDraw3D.new_scoped_config().set_thickness(0).set_center_brightness(0.1) + # Draw with a thickness of 0 + DebugDraw3D.draw_box(Vector3.ZERO, Quaternion.IDENTITY, Vector3.ONE, Color.RED) + # If necessary, the values inside this scope can be changed + # even before each call to draw_*. + _s.set_thickness(0.05) + DebugDraw3D.draw_box(Vector3(1,0,1), Quaternion.IDENTITY, Vector3.ONE * 1, Color.BLUE_VIOLET) +``` + +![screenshot_5](/images/screenshot_5.png) + +> [!TIP] +> +> If you want to use a non-standard Viewport for rendering a 3d scene, then do not forget to specify it in the scoped config! + +## API + +This project has a separate [documentation](https://dd3d.dmitriysalnikov.ru/docs/) page. + +Also, a list of all functions is available in the documentation inside the editor (see `DebugDraw3D` and `DebugDraw2D`). + +![screenshot_4](/images/screenshot_4.png) + +## Known issues and limitations + +The text in the keys and values of a text group cannot contain multi-line strings. + +The entire text overlay can only be placed in one corner. + +[Frustum of Camera3D does not take into account the window size from ProjectSettings](https://github.com/godotengine/godot/issues/70362). + +## More screenshots + +`DebugDrawDemoScene.tscn` in editor +![screenshot_2](/images/screenshot_2.png) + +`DebugDrawDemoScene.tscn` in play mode +![screenshot_3](/images/screenshot_3.png) diff --git a/addons/debug_draw_3d/debug_draw_3d.gdextension b/addons/debug_draw_3d/debug_draw_3d.gdextension new file mode 100644 index 0000000..cead527 --- /dev/null +++ b/addons/debug_draw_3d/debug_draw_3d.gdextension @@ -0,0 +1,153 @@ +[configuration] + +entry_symbol = "debug_draw_3d_library_init" +compatibility_minimum = "4.2.2" +reloadable = false + +[dependencies] + +; example.x86_64 = { "relative or absolute path to the dependency" : "the path relative to the exported project", } +; ------------------------------------- +; debug + +macos = { } +windows.x86_64 = { } +linux.x86_64 = { } + +; by default godot is using threads +web.wasm32.nothreads = {} +web.wasm32 = {} + +android.arm32 = { } +android.arm64 = { } +android.x86_32 = { } +android.x86_64 = { } + +ios = {} + +; ------------------------------------- +; release no debug draw + +macos.template_release = { } +windows.template_release.x86_64 = { } +linux.template_release.x86_64 = { } + +web.template_release.wasm32.nothreads = { } +web.template_release.wasm32 = { } + +android.template_release.arm32 = { } +android.template_release.arm64 = { } +android.template_release.x86_32 = { } +android.template_release.x86_64 = { } + +ios.template_release = {} + +; ------------------------------------- +; release forced debug draw + +macos.template_release.forced_dd3d = { } +windows.template_release.x86_64.forced_dd3d = { } +linux.template_release.x86_64.forced_dd3d = { } + +web.template_release.wasm32.nothreads.forced_dd3d = { } +web.template_release.wasm32.forced_dd3d = { } + +ios.template_release.forced_dd3d = {} + +[libraries] + +; ------------------------------------- +; debug + +macos = "libs/libdd3d.macos.editor.universal.framework" +windows.x86_64 = "libs/libdd3d.windows.editor.x86_64.dll" +linux.x86_64 = "libs/libdd3d.linux.editor.x86_64.so" + +web.wasm32.nothreads = "libs/libdd3d.web.template_debug.wasm32.wasm" +web.wasm32 = "libs/libdd3d.web.template_debug.wasm32.threads.wasm" + +android.arm32 = "libs/libdd3d.android.template_debug.arm32.so" +android.arm64 = "libs/libdd3d.android.template_debug.arm64.so" +android.x86_32 = "libs/libdd3d.android.template_debug.x86_32.so" +android.x86_64 = "libs/libdd3d.android.template_debug.x86_64.so" + +ios = "libs/libdd3d.ios.template_debug.universal.dylib" + +; ------------------------------------- +; release no debug draw + +macos.template_release = "libs/libdd3d.macos.template_release.universal.framework" +windows.template_release.x86_64 = "libs/libdd3d.windows.template_release.x86_64.dll" +linux.template_release.x86_64 = "libs/libdd3d.linux.template_release.x86_64.so" + +web.template_release.wasm32.nothreads = "libs/libdd3d.web.template_release.wasm32.wasm" +web.template_release.wasm32 = "libs/libdd3d.web.template_release.wasm32.threads.wasm" + +android.template_release.arm32 = "libs/libdd3d.android.template_release.arm32.so" +android.template_release.arm64 = "libs/libdd3d.android.template_release.arm64.so" +android.template_release.x86_32 = "libs/libdd3d.android.template_release.x86_32.so" +android.template_release.x86_64 = "libs/libdd3d.android.template_release.x86_64.so" + +ios.template_release = "libs/libdd3d.ios.template_release.universal.dylib" + +; ------------------------------------- +; release forced debug draw + +macos.template_release.forced_dd3d = "libs/libdd3d.macos.template_release.universal.enabled.framework" +windows.template_release.x86_64.forced_dd3d = "libs/libdd3d.windows.template_release.x86_64.enabled.dll" +linux.template_release.x86_64.forced_dd3d = "libs/libdd3d.linux.template_release.x86_64.enabled.so" + +web.template_release.wasm32.nothreads.forced_dd3d = "libs/libdd3d.web.template_release.wasm32.enabled.wasm" +web.template_release.wasm32.forced_dd3d = "libs/libdd3d.web.template_release.wasm32.threads.enabled.wasm" + +ios.template_release.forced_dd3d = "libs/libdd3d.ios.template_release.universal.enabled.dylib" + +; ------------------------------------- +; DOUBLE PRECISION +; ------------------------------------- + +; ------------------------------------- +; debug + +macos.double = "libs/libdd3d.macos.editor.universal.double.framework" +windows.x86_64.double = "libs/libdd3d.windows.editor.x86_64.double.dll" +linux.x86_64.double = "libs/libdd3d.linux.editor.x86_64.double.so" + +web.wasm32.nothreads.double = "libs/libdd3d.web.template_debug.wasm32.double.wasm" +web.wasm32.double = "libs/libdd3d.web.template_debug.wasm32.threads.double.wasm" + +android.arm32.double = "libs/libdd3d.android.template_debug.arm32.double.so" +android.arm64.double = "libs/libdd3d.android.template_debug.arm64.double.so" +android.x86_32.double = "libs/libdd3d.android.template_debug.x86_32.double.so" +android.x86_64.double = "libs/libdd3d.android.template_debug.x86_64.double.so" + +ios.double = "libs/libdd3d.ios.template_debug.universal.dylib" + +; ------------------------------------- +; release no debug draw + +macos.template_release.double = "libs/libdd3d.macos.template_release.universal.double.framework" +windows.template_release.x86_64.double = "libs/libdd3d.windows.template_release.x86_64.double.dll" +linux.template_release.x86_64.double = "libs/libdd3d.linux.template_release.x86_64.double.so" + +web.template_release.wasm32.nothreads.double = "libs/libdd3d.web.template_release.wasm32.double.wasm" +web.template_release.wasm32.double = "libs/libdd3d.web.template_release.wasm32.threads.double.wasm" + +android.template_release.arm32.double = "libs/libdd3d.android.template_release.arm32.double.so" +android.template_release.arm64.double = "libs/libdd3d.android.template_release.arm64.double.so" +android.template_release.x86_32.double = "libs/libdd3d.android.template_release.x86_32.double.so" +android.template_release.x86_64.double = "libs/libdd3d.android.template_release.x86_64.double.so" + +ios.template_release.double = "libs/libdd3d.ios.template_release.universal.double.dylib" + +; ------------------------------------- +; release forced debug draw + +macos.template_release.forced_dd3d.double = "libs/libdd3d.macos.template_release.universal.enabled.double.framework" +windows.template_release.x86_64.forced_dd3d.double = "libs/libdd3d.windows.template_release.x86_64.enabled.double.dll" +linux.template_release.x86_64.forced_dd3d.double = "libs/libdd3d.linux.template_release.x86_64.enabled.double.so" + +web.template_release.wasm32.nothreads.forced_dd3d.double = "libs/libdd3d.web.template_release.wasm32.enabled.double.wasm" +web.template_release.wasm32.forced_dd3d.double = "libs/libdd3d.web.template_release.wasm32.threads.enabled.double.wasm" + +ios.template_release.forced_dd3d.double = "libs/libdd3d.ios.template_release.universal.enabled.double.dylib" diff --git a/addons/debug_draw_3d/debug_draw_3d.gdextension.uid b/addons/debug_draw_3d/debug_draw_3d.gdextension.uid new file mode 100644 index 0000000..15da0d3 --- /dev/null +++ b/addons/debug_draw_3d/debug_draw_3d.gdextension.uid @@ -0,0 +1 @@ +uid://svqaxfp5kyrl diff --git a/addons/debug_draw_3d/libs/.gdignore b/addons/debug_draw_3d/libs/.gdignore new file mode 100644 index 0000000..e69de29 diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_debug.arm32.so b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.arm32.so new file mode 100644 index 0000000..388f178 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.arm32.so differ diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_debug.arm64.so b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.arm64.so new file mode 100644 index 0000000..1166b25 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.arm64.so differ diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_debug.x86_32.so b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.x86_32.so new file mode 100644 index 0000000..4f87efd Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.x86_32.so differ diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_debug.x86_64.so b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.x86_64.so new file mode 100644 index 0000000..7228e89 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.android.template_debug.x86_64.so differ diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_release.arm32.so b/addons/debug_draw_3d/libs/libdd3d.android.template_release.arm32.so new file mode 100644 index 0000000..6270ce3 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.android.template_release.arm32.so differ diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_release.arm64.so b/addons/debug_draw_3d/libs/libdd3d.android.template_release.arm64.so new file mode 100644 index 0000000..a66e7b2 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.android.template_release.arm64.so differ diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_release.x86_32.so b/addons/debug_draw_3d/libs/libdd3d.android.template_release.x86_32.so new file mode 100644 index 0000000..528a3d1 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.android.template_release.x86_32.so differ diff --git a/addons/debug_draw_3d/libs/libdd3d.android.template_release.x86_64.so b/addons/debug_draw_3d/libs/libdd3d.android.template_release.x86_64.so new file mode 100644 index 0000000..2f25e64 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.android.template_release.x86_64.so differ diff --git a/addons/debug_draw_3d/libs/libdd3d.ios.template_debug.universal.dylib b/addons/debug_draw_3d/libs/libdd3d.ios.template_debug.universal.dylib new file mode 100644 index 0000000..2e3e052 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.ios.template_debug.universal.dylib differ diff --git a/addons/debug_draw_3d/libs/libdd3d.ios.template_release.universal.dylib b/addons/debug_draw_3d/libs/libdd3d.ios.template_release.universal.dylib new file mode 100644 index 0000000..cf8fb54 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.ios.template_release.universal.dylib differ diff --git a/addons/debug_draw_3d/libs/libdd3d.ios.template_release.universal.enabled.dylib b/addons/debug_draw_3d/libs/libdd3d.ios.template_release.universal.enabled.dylib new file mode 100644 index 0000000..a24b083 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.ios.template_release.universal.enabled.dylib differ diff --git a/addons/debug_draw_3d/libs/libdd3d.linux.editor.x86_64.so b/addons/debug_draw_3d/libs/libdd3d.linux.editor.x86_64.so new file mode 100644 index 0000000..756cb15 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.linux.editor.x86_64.so differ diff --git a/addons/debug_draw_3d/libs/libdd3d.linux.template_release.x86_64.enabled.so b/addons/debug_draw_3d/libs/libdd3d.linux.template_release.x86_64.enabled.so new file mode 100644 index 0000000..457ef8c Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.linux.template_release.x86_64.enabled.so differ diff --git a/addons/debug_draw_3d/libs/libdd3d.linux.template_release.x86_64.so b/addons/debug_draw_3d/libs/libdd3d.linux.template_release.x86_64.so new file mode 100644 index 0000000..776475e Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.linux.template_release.x86_64.so differ diff --git a/addons/debug_draw_3d/libs/libdd3d.macos.editor.universal.framework/Resources/Info.plist b/addons/debug_draw_3d/libs/libdd3d.macos.editor.universal.framework/Resources/Info.plist new file mode 100644 index 0000000..ab50767 --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.macos.editor.universal.framework/Resources/Info.plist @@ -0,0 +1,33 @@ + + + + + CFBundleInfoDictionaryVersion + 6.0 + CFBundleDevelopmentRegion + en + CFBundleExecutable + libdd3d.macos.editor.universal.dylib + CFBundleName + Debug Draw 3D + CFBundleDisplayName + Debug Draw 3D + CFBundleIdentifier + ru.dmitriysalnikov.dd3d + NSHumanReadableCopyright + Copyright (c) Dmitriy Salnikov. + CFBundleVersion + 1.5.0 + CFBundleShortVersionString + 1.5.0 + CFBundlePackageType + FMWK + CSResourcesFileMapped + + DTPlatformName + macosx + LSMinimumSystemVersion + 10.14 + + + \ No newline at end of file diff --git a/addons/debug_draw_3d/libs/libdd3d.macos.editor.universal.framework/libdd3d.macos.editor.universal.dylib b/addons/debug_draw_3d/libs/libdd3d.macos.editor.universal.framework/libdd3d.macos.editor.universal.dylib new file mode 100644 index 0000000..f7e3f44 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.macos.editor.universal.framework/libdd3d.macos.editor.universal.dylib differ diff --git a/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.enabled.framework/Resources/Info.plist b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.enabled.framework/Resources/Info.plist new file mode 100644 index 0000000..be48360 --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.enabled.framework/Resources/Info.plist @@ -0,0 +1,33 @@ + + + + + CFBundleInfoDictionaryVersion + 6.0 + CFBundleDevelopmentRegion + en + CFBundleExecutable + libdd3d.macos.template_release.universal.enabled.dylib + CFBundleName + Debug Draw 3D + CFBundleDisplayName + Debug Draw 3D + CFBundleIdentifier + ru.dmitriysalnikov.dd3d + NSHumanReadableCopyright + Copyright (c) Dmitriy Salnikov. + CFBundleVersion + 1.5.0 + CFBundleShortVersionString + 1.5.0 + CFBundlePackageType + FMWK + CSResourcesFileMapped + + DTPlatformName + macosx + LSMinimumSystemVersion + 10.14 + + + \ No newline at end of file diff --git a/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.enabled.framework/libdd3d.macos.template_release.universal.enabled.dylib b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.enabled.framework/libdd3d.macos.template_release.universal.enabled.dylib new file mode 100644 index 0000000..92958df Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.enabled.framework/libdd3d.macos.template_release.universal.enabled.dylib differ diff --git a/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.framework/Resources/Info.plist b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.framework/Resources/Info.plist new file mode 100644 index 0000000..02284de --- /dev/null +++ b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.framework/Resources/Info.plist @@ -0,0 +1,33 @@ + + + + + CFBundleInfoDictionaryVersion + 6.0 + CFBundleDevelopmentRegion + en + CFBundleExecutable + libdd3d.macos.template_release.universal.dylib + CFBundleName + Debug Draw 3D + CFBundleDisplayName + Debug Draw 3D + CFBundleIdentifier + ru.dmitriysalnikov.dd3d + NSHumanReadableCopyright + Copyright (c) Dmitriy Salnikov. + CFBundleVersion + 1.5.0 + CFBundleShortVersionString + 1.5.0 + CFBundlePackageType + FMWK + CSResourcesFileMapped + + DTPlatformName + macosx + LSMinimumSystemVersion + 10.14 + + + \ No newline at end of file diff --git a/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.framework/libdd3d.macos.template_release.universal.dylib b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.framework/libdd3d.macos.template_release.universal.dylib new file mode 100644 index 0000000..9f6e7fa Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.macos.template_release.universal.framework/libdd3d.macos.template_release.universal.dylib differ diff --git a/addons/debug_draw_3d/libs/libdd3d.web.template_debug.wasm32.threads.wasm b/addons/debug_draw_3d/libs/libdd3d.web.template_debug.wasm32.threads.wasm new file mode 100644 index 0000000..d141395 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.web.template_debug.wasm32.threads.wasm differ diff --git a/addons/debug_draw_3d/libs/libdd3d.web.template_debug.wasm32.wasm b/addons/debug_draw_3d/libs/libdd3d.web.template_debug.wasm32.wasm new file mode 100644 index 0000000..71c53e5 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.web.template_debug.wasm32.wasm differ diff --git a/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.enabled.wasm b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.enabled.wasm new file mode 100644 index 0000000..6c796d7 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.enabled.wasm differ diff --git a/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.threads.enabled.wasm b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.threads.enabled.wasm new file mode 100644 index 0000000..7611a50 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.threads.enabled.wasm differ diff --git a/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.threads.wasm b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.threads.wasm new file mode 100644 index 0000000..3fe340a Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.threads.wasm differ diff --git a/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.wasm b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.wasm new file mode 100644 index 0000000..dbc9d49 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.web.template_release.wasm32.wasm differ diff --git a/addons/debug_draw_3d/libs/libdd3d.windows.editor.x86_64.dll b/addons/debug_draw_3d/libs/libdd3d.windows.editor.x86_64.dll new file mode 100644 index 0000000..70df5e3 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.windows.editor.x86_64.dll differ diff --git a/addons/debug_draw_3d/libs/libdd3d.windows.template_release.x86_64.dll b/addons/debug_draw_3d/libs/libdd3d.windows.template_release.x86_64.dll new file mode 100644 index 0000000..544e405 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.windows.template_release.x86_64.dll differ diff --git a/addons/debug_draw_3d/libs/libdd3d.windows.template_release.x86_64.enabled.dll b/addons/debug_draw_3d/libs/libdd3d.windows.template_release.x86_64.enabled.dll new file mode 100644 index 0000000..018c573 Binary files /dev/null and b/addons/debug_draw_3d/libs/libdd3d.windows.template_release.x86_64.enabled.dll differ diff --git a/addons/git_describe/LICENSE b/addons/git_describe/LICENSE new file mode 100644 index 0000000..42989c8 --- /dev/null +++ b/addons/git_describe/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Joseph Michael Ware (zibetnu) + +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. diff --git a/addons/git_describe/debugger.gd b/addons/git_describe/debugger.gd new file mode 100644 index 0000000..41bf2bc --- /dev/null +++ b/addons/git_describe/debugger.gd @@ -0,0 +1,7 @@ +extends EditorDebuggerPlugin + +var erase_describe_callable: Callable + + +func _setup_session(session_id: int) -> void: + get_session(session_id).stopped.connect(erase_describe_callable) diff --git a/addons/git_describe/debugger.gd.uid b/addons/git_describe/debugger.gd.uid new file mode 100644 index 0000000..f4c4461 --- /dev/null +++ b/addons/git_describe/debugger.gd.uid @@ -0,0 +1 @@ +uid://bw5gogl4u1dv2 diff --git a/addons/git_describe/exporter.gd b/addons/git_describe/exporter.gd new file mode 100644 index 0000000..6820fe2 --- /dev/null +++ b/addons/git_describe/exporter.gd @@ -0,0 +1,21 @@ +extends EditorExportPlugin + +var set_describe_callable: Callable +var erase_describe_callable: Callable + + +func _get_name() -> String: + return "godot_git_describe_exporter" + + +func _export_begin( + _features: PackedStringArray, + _is_debug: bool, + _path: String, + _flags: int +) -> void: + set_describe_callable.call() + + +func _export_end() -> void: + erase_describe_callable.call() diff --git a/addons/git_describe/exporter.gd.uid b/addons/git_describe/exporter.gd.uid new file mode 100644 index 0000000..49b167c --- /dev/null +++ b/addons/git_describe/exporter.gd.uid @@ -0,0 +1 @@ +uid://kfijvsqec6mn diff --git a/addons/git_describe/label/git_describe_label.gd b/addons/git_describe/label/git_describe_label.gd new file mode 100644 index 0000000..7ea49c0 --- /dev/null +++ b/addons/git_describe/label/git_describe_label.gd @@ -0,0 +1,22 @@ +@icon("icon.svg") +class_name GitDescribeLabel +extends Label +## A label for automatically displaying Git describe strings. + + +func _ready() -> void: + set_text_to_describe() + + +## Sets [member Label.text] to the describe string unless the string is empty. +## Called on [signal Node.ready]. +func set_text_to_describe() -> void: + var describe_setting: String = ProjectSettings.get_setting( + "addons/git_describe/describe_setting_path", + "application/config/git_describe" + ) + var describe: String = ProjectSettings.get_setting(describe_setting, "") + if describe.is_empty(): + return + + text = describe diff --git a/addons/git_describe/label/git_describe_label.gd.uid b/addons/git_describe/label/git_describe_label.gd.uid new file mode 100644 index 0000000..578c0d5 --- /dev/null +++ b/addons/git_describe/label/git_describe_label.gd.uid @@ -0,0 +1 @@ +uid://cwjb3x45e2r4k diff --git a/addons/git_describe/label/icon.svg b/addons/git_describe/label/icon.svg new file mode 100644 index 0000000..28d93cc --- /dev/null +++ b/addons/git_describe/label/icon.svg @@ -0,0 +1,2 @@ + + diff --git a/addons/git_describe/label/icon.svg.import b/addons/git_describe/label/icon.svg.import new file mode 100644 index 0000000..410cd97 --- /dev/null +++ b/addons/git_describe/label/icon.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cwdtl2gnx5fs1" +path="res://.godot/imported/icon.svg-a1143e7d78a969bea3b43f8481309a20.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/git_describe/label/icon.svg" +dest_files=["res://.godot/imported/icon.svg-a1143e7d78a969bea3b43f8481309a20.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 diff --git a/addons/git_describe/platforms.cfg b/addons/git_describe/platforms.cfg new file mode 100644 index 0000000..8d8685b --- /dev/null +++ b/addons/git_describe/platforms.cfg @@ -0,0 +1,18 @@ +[Linux] + +path="bash" +arguments=["-c"] +which="which" + +[Steam Linux Runtime] + +; https://gitlab.steamos.cloud/steamrt/steam-runtime-tools/-/blob/main/docs/slr-for-game-developers.md#running-commands-outside-the-container +path="steam-runtime-launch-client" +arguments=["--alongside-steam", "--host", "-c"] +which="which" + +[Windows] + +path="cmd.exe" +arguments=["/C"] +which="where" diff --git a/addons/git_describe/plugin.cfg b/addons/git_describe/plugin.cfg new file mode 100644 index 0000000..846c2e1 --- /dev/null +++ b/addons/git_describe/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Godot Git Describe" +description="Seamlessly display in-game versions based on your Git tags." +author="zibetnu" +version="0.4.0" +script="plugin.gd" diff --git a/addons/git_describe/plugin.gd b/addons/git_describe/plugin.gd new file mode 100644 index 0000000..108fab7 --- /dev/null +++ b/addons/git_describe/plugin.gd @@ -0,0 +1,49 @@ +@tool +extends EditorPlugin + +const Debugger = preload("debugger.gd") +const Exporter = preload("exporter.gd") +const Settings = preload("settings.gd") +const Utilities = preload("utilities.gd") + +var debugger := Debugger.new() +var exporter := Exporter.new() + + +func _enter_tree() -> void: + debugger.erase_describe_callable = _erase_describe + exporter.erase_describe_callable = _erase_describe + exporter.set_describe_callable = _set_describe + + add_debugger_plugin(debugger) + add_export_plugin(exporter) + Settings.init_settings() + Utilities.push_status() + + +func _build() -> bool: + _set_describe() + return true + + +func _disable_plugin() -> void: + remove_debugger_plugin(debugger) + remove_export_plugin(exporter) + _erase_describe() + + +func _exit_tree() -> void: + _disable_plugin() + + +func _set_describe() -> void: + var describe: String = Utilities.get_git_describe( + Settings.get_command_options() + ) + Settings.set_describe_setting(describe) + Settings.append_project_name(describe, true) + + +func _erase_describe() -> void: + Settings.set_describe_setting(null) + Settings.append_project_name(Settings.cached_describe, false) diff --git a/addons/git_describe/plugin.gd.uid b/addons/git_describe/plugin.gd.uid new file mode 100644 index 0000000..cbc05b9 --- /dev/null +++ b/addons/git_describe/plugin.gd.uid @@ -0,0 +1 @@ +uid://dl32ptguu3hex diff --git a/addons/git_describe/settings.gd b/addons/git_describe/settings.gd new file mode 100644 index 0000000..9efc422 --- /dev/null +++ b/addons/git_describe/settings.gd @@ -0,0 +1,71 @@ +@tool +extends RefCounted + +const BASE = "addons/git_describe/" + +const SETTING_PATH_SETTING = BASE + "describe_setting_path" +const DEFAULT_SETTING_PATH = "application/config/git_describe" + +const APPEND_PROJECT_NAME_SETTING = BASE + "append_describe_to_project_name" +const DEFAULT_APPEND_PROJECT_NAME = false +const PROJECT_NAME_SETTING = "application/config/name" + +const COMMAND_OPTIONS_SETTING = BASE + "command_options" +const DEFAULT_COMMAND_OPTIONS = "--always" + +static var cached_describe: String + + +static func init_setting( + setting_name: String, + initial_value: Variant, + basic := true +) -> void: + if not ProjectSettings.has_setting(setting_name): + ProjectSettings.set_setting(setting_name, initial_value) + + ProjectSettings.set_as_basic(setting_name, basic) + ProjectSettings.set_initial_value(setting_name, initial_value) + + +static func init_settings() -> void: + init_setting(SETTING_PATH_SETTING, DEFAULT_SETTING_PATH) + init_setting(APPEND_PROJECT_NAME_SETTING, DEFAULT_APPEND_PROJECT_NAME) + init_setting(COMMAND_OPTIONS_SETTING, DEFAULT_COMMAND_OPTIONS, false) + + +static func append_project_name(describe: String, append: bool) -> void: + if not ProjectSettings.get_setting(APPEND_PROJECT_NAME_SETTING, false): + return + + var project_name: String = ProjectSettings.get_setting( + PROJECT_NAME_SETTING + ) + var separated_describe: String = " " + describe + match [append, project_name.ends_with(separated_describe)]: + [false, true]: + cached_describe = "" + project_name = project_name.replace(separated_describe, "") + + [true, false]: + cached_describe = describe + project_name += separated_describe + + ProjectSettings.set_setting(PROJECT_NAME_SETTING, project_name) + ProjectSettings.save() + + +static func get_command_options() -> String: + return ProjectSettings.get_setting( + COMMAND_OPTIONS_SETTING, + DEFAULT_COMMAND_OPTIONS + ) + + +static func set_describe_setting(value: Variant) -> void: + var describe_setting: String = ProjectSettings.get_setting( + SETTING_PATH_SETTING, + DEFAULT_SETTING_PATH + ) + ProjectSettings.set_setting(describe_setting, value) + ProjectSettings.save() diff --git a/addons/git_describe/settings.gd.uid b/addons/git_describe/settings.gd.uid new file mode 100644 index 0000000..23991cd --- /dev/null +++ b/addons/git_describe/settings.gd.uid @@ -0,0 +1 @@ +uid://3xjrlqx5le22 diff --git a/addons/git_describe/utilities.gd b/addons/git_describe/utilities.gd new file mode 100644 index 0000000..41ee1ce --- /dev/null +++ b/addons/git_describe/utilities.gd @@ -0,0 +1,111 @@ +@tool +extends RefCounted + +const CONFIG_PATH = "res://addons/git_describe/platforms.cfg" +const REPOSITORY_PATH = "res://" + +static var platform_config: ConfigFile = load_platform_config() + + +static func execute(command: String) -> Results: + var platform_name: String = get_platform_name() + var path: String = platform_config.get_value(platform_name, "path", "") + + var arguments: Array[String] = [] + arguments.assign( + platform_config.get_value(platform_name, "arguments", "") as Array + ) + arguments.append(command) + + var output: Array[String] = [] + var exit_code: int = OS.execute(path, arguments, output, true) + return Results.new(output, exit_code) + + +static func get_git_describe(options := "") -> String: + const DEFAULT_GIT_DESCRIBE = "" + if not is_git_repository_found(): + return DEFAULT_GIT_DESCRIBE + + if not is_git_found(): + return DEFAULT_GIT_DESCRIBE + + var results: Results = execute("git describe " + options) + if results.exit_code != 0: + return DEFAULT_GIT_DESCRIBE + + return results.output[0].strip_edges() + + +static func get_platform_name() -> String: + if is_in_steam_runtime(): + return "Steam Linux Runtime" + + return OS.get_name() + + +static func is_git_found() -> bool: + var which: String = platform_config.get_value( + get_platform_name(), "which", "" + ) + var results: Results = execute(" ".join([which, "git"])) + return results.exit_code == 0 and not results.output[0].is_empty() + + +static func is_git_repository_found() -> bool: + return DirAccess.dir_exists_absolute(REPOSITORY_PATH.path_join(".git")) + + +# gdlint:ignore = max-line-length +# https://gitlab.steamos.cloud/steamrt/steam-runtime-tools/-/blob/main/docs/slr-for-game-developers.md#detecting-the-container-environment +static func is_in_steam_runtime() -> bool: + if OS.get_name() != "Linux": + return false + + const CAT_COMMAND = "cat" + var output: Array[String] = [] + OS.execute(CAT_COMMAND, ["/etc/os-release"], output) + OS.execute(CAT_COMMAND, ["/run/host/container-manager"], output) + return "steamrt" in output[0] or "pressure-vessel" in output[1] + + +static func is_platform_configured() -> bool: + return get_platform_name() in platform_config.get_sections() + + +static func load_platform_config() -> ConfigFile: + var config := ConfigFile.new() + config.load(CONFIG_PATH) + return config + + +static func push_status() -> void: + const PRINT_ID = "Godot Git Describe: " + if not is_platform_configured(): + push_error( + PRINT_ID, + "\"%s\" configuration not found in \"%s\"." % [ + get_platform_name(), + CONFIG_PATH + ] + ) + + elif not is_git_repository_found(): + push_error( + PRINT_ID, + "Git repository not found in \"%s\"." + % ProjectSettings.globalize_path(REPOSITORY_PATH) + ) + + elif not is_git_found(): + push_error(PRINT_ID, "Git not found.") + + +class Results: + var output: Array[String] + var exit_code: int + + @warning_ignore("shadowed_variable") + func _init(output: Array[String] = [], exit_code := 0) -> void: + self.output = output + self.exit_code = exit_code diff --git a/addons/git_describe/utilities.gd.uid b/addons/git_describe/utilities.gd.uid new file mode 100644 index 0000000..c6d6d90 --- /dev/null +++ b/addons/git_describe/utilities.gd.uid @@ -0,0 +1 @@ +uid://1gbfdpfhngs1 diff --git a/addons/godot-git-plugin/LICENSE b/addons/godot-git-plugin/LICENSE new file mode 100644 index 0000000..f153fb8 --- /dev/null +++ b/addons/godot-git-plugin/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016-2023 The Godot Engine community + +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. diff --git a/addons/godot-git-plugin/THIRDPARTY.md b/addons/godot-git-plugin/THIRDPARTY.md new file mode 100644 index 0000000..837488f --- /dev/null +++ b/addons/godot-git-plugin/THIRDPARTY.md @@ -0,0 +1,1349 @@ +# Third-Party Notices + +The Godot Git Plugin source code uses the following third-party source code: + +1. godotengine/godot-cpp - MIT License - https://github.com/godotengine/godot-cpp/tree/02336831735fd6affbe0a6fa252ec98d3e78120c +2. libgit2/libgit2 - GPLv2 with a special Linking Exception - https://github.com/libgit2/libgit2/tree/b7bad55e4bb0a285b073ba5e02b01d3f522fc95d +3. libssh2/libssh2 - BSD-3-Clause License - https://github.com/libssh2/libssh2/tree/635caa90787220ac3773c1d5ba11f1236c22eae8 + +We also link to these third-party libraries (only in the compiled binary form): + +1. OpenSSL - Only on Linux and MacOS - OpenSSL License - http://www.openssl.org/source/openssl-1.1.1s.tar.gz + +## License Texts + +### godotengine/godot-cpp + +``` +# MIT License + +Copyright (c) 2017-2022 Godot Engine contributors. + +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. +``` + +### libgit2/libgit2 + +``` + libgit2 is Copyright (C) the libgit2 contributors, + unless otherwise stated. See the AUTHORS file for details. + + Note that the only valid version of the GPL as far as this project + is concerned is _this_ particular version of the license (ie v2, not + v2.2 or v3.x or whatever), unless explicitly otherwise stated. + +---------------------------------------------------------------------- + + LINKING EXCEPTION + + In addition to the permissions in the GNU General Public License, + the authors give you unlimited permission to link the compiled + version of this library into combinations with other programs, + and to distribute those combinations without any restriction + coming from the use of this file. (The General Public License + restrictions do apply in other respects; for example, they cover + modification of the file, and distribution when not linked into + a combined executable.) + +---------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +---------------------------------------------------------------------- + +The bundled ZLib code is licensed under the ZLib license: + +Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +---------------------------------------------------------------------- + +The Clar framework is licensed under the ISC license: + +Copyright (c) 2011-2015 Vicent Marti + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---------------------------------------------------------------------- + +The regex library (deps/regex/) is licensed under the GNU LGPL +(available at the end of this file). + +Definitions for data structures and routines for the regular +expression library. + +Copyright (C) 1985,1989-93,1995-98,2000,2001,2002,2003,2005,2006,2008 +Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with the GNU C Library; if not, write to the Free +Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +---------------------------------------------------------------------- + +The bundled winhttp definition files (deps/winhttp/) are licensed under +the GNU LGPL (available at the end of this file). + +Copyright (C) 2007 Francois Gouget + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +---------------------------------------------------------------------- + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + +---------------------------------------------------------------------- + +The bundled SHA1 collision detection code is licensed under the MIT license: + +MIT License + +Copyright (c) 2017: + Marc Stevens + Cryptology Group + Centrum Wiskunde & Informatica + P.O. Box 94079, 1090 GB Amsterdam, Netherlands + marc@marc-stevens.nl + + Dan Shumow + Microsoft Research + danshu@microsoft.com + +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. + +---------------------------------------------------------------------- + +The bundled wildmatch code is licensed under the BSD license: + +Copyright Rich Salz. +All rights reserved. + +Redistribution and use in any form are permitted provided that the +following restrictions are are met: + +1. Source distributions must retain this entire copyright notice + and comment. +2. Binary distributions must include the acknowledgement ``This + product includes software developed by Rich Salz'' in the + documentation or other materials provided with the + distribution. This must not be represented as an endorsement + or promotion without specific prior written permission. +3. The origin of this software must not be misrepresented, either + by explicit claim or by omission. Credits must appear in the + source and documentation. +4. Altered versions must be plainly marked as such in the source + and documentation and must not be misrepresented as being the + original software. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +---------------------------------------------------------------------- + +Portions of the OpenSSL headers are included under the OpenSSL license: + +Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) +All rights reserved. + +This package is an SSL implementation written +by Eric Young (eay@cryptsoft.com). +The implementation was written so as to conform with Netscapes SSL. + +This library is free for commercial and non-commercial use as long as +the following conditions are aheared to. The following conditions +apply to all code found in this distribution, be it the RC4, RSA, +lhash, DES, etc., code; not just the SSL code. The SSL documentation +included with this distribution is covered by the same copyright terms +except that the holder is Tim Hudson (tjh@cryptsoft.com). + +Copyright remains Eric Young's, and as such any Copyright notices in +the code are not to be removed. +If this package is used in a product, Eric Young should be given attribution +as the author of the parts of the library used. +This can be in the form of a textual message at program startup or +in documentation (online or textual) provided with the package. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + "This product includes cryptographic software written by + Eric Young (eay@cryptsoft.com)" + The word 'cryptographic' can be left out if the rouines from the library + being used are not cryptographic related :-). +4. If you include any Windows specific code (or a derivative thereof) from + the apps directory (application code) you must include an acknowledgement: + "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + +THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +The licence and distribution terms for any publically available version or +derivative of this code cannot be changed. i.e. this code cannot simply be +copied and put under another distribution licence +[including the GNU Public Licence.] + +==================================================================== +Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + "This product includes software developed by the OpenSSL Project + for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + +4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + endorse or promote products derived from this software without + prior written permission. For written permission, please contact + openssl-core@openssl.org. + +5. Products derived from this software may not be called "OpenSSL" + nor may "OpenSSL" appear in their names without prior written + permission of the OpenSSL Project. + +6. Redistributions of any form whatsoever must retain the following + acknowledgment: + "This product includes software developed by the OpenSSL Project + for use in the OpenSSL Toolkit (http://www.openssl.org/)" + +THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY +EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR +ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. +``` + +### libssh2/libssh2 + +``` +/* Copyright (c) 2004-2007 Sara Golemon + * Copyright (c) 2005,2006 Mikhail Gusarov + * Copyright (c) 2006-2007 The Written Word, Inc. + * Copyright (c) 2007 Eli Fant + * Copyright (c) 2009-2021 Daniel Stenberg + * Copyright (C) 2008, 2009 Simon Josefsson + * Copyright (c) 2000 Markus Friedl + * Copyright (c) 2015 Microsoft Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ +``` + +### OpenSSL + +``` + + LICENSE ISSUES + ============== + + The OpenSSL toolkit stays under a double license, i.e. both the conditions of + the OpenSSL License and the original SSLeay license apply to the toolkit. + See below for the actual license texts. + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2019 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +``` diff --git a/addons/godot-git-plugin/git_plugin.gdextension b/addons/godot-git-plugin/git_plugin.gdextension new file mode 100644 index 0000000..49fffbf --- /dev/null +++ b/addons/godot-git-plugin/git_plugin.gdextension @@ -0,0 +1,12 @@ +[configuration] + +entry_symbol = "git_plugin_init" +compatibility_minimum = "4.1.0" + +[libraries] + +macos.editor = "macos/libgit_plugin.macos.editor.universal.dylib" +windows.editor.x86_64 = "win64/libgit_plugin.windows.editor.x86_64.dll" +linux.editor.x86_64 = "linux/libgit_plugin.linux.editor.x86_64.so" +linux.editor.arm64 = "linux/libgit_plugin.linux.editor.arm64.so" +linux.editor.rv64 = "" diff --git a/addons/godot-git-plugin/git_plugin.gdextension.uid b/addons/godot-git-plugin/git_plugin.gdextension.uid new file mode 100644 index 0000000..bfd0b1f --- /dev/null +++ b/addons/godot-git-plugin/git_plugin.gdextension.uid @@ -0,0 +1 @@ +uid://gmi3jeghe2j8 diff --git a/addons/godot-git-plugin/linux/libgit_plugin.linux.editor.x86_64.so b/addons/godot-git-plugin/linux/libgit_plugin.linux.editor.x86_64.so new file mode 100644 index 0000000..8dab6db Binary files /dev/null and b/addons/godot-git-plugin/linux/libgit_plugin.linux.editor.x86_64.so differ diff --git a/addons/godot-git-plugin/macos/libgit_plugin.macos.editor.universal.dylib b/addons/godot-git-plugin/macos/libgit_plugin.macos.editor.universal.dylib new file mode 100644 index 0000000..644aa2a Binary files /dev/null and b/addons/godot-git-plugin/macos/libgit_plugin.macos.editor.universal.dylib differ diff --git a/addons/godot-git-plugin/plugin.cfg b/addons/godot-git-plugin/plugin.cfg new file mode 100644 index 0000000..9c4e36f --- /dev/null +++ b/addons/godot-git-plugin/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Godot Git Plugin" +description="This plugin lets you interact with Git without leaving the Godot editor. More information can be found at https://github.com/godotengine/godot-git-plugin/wiki" +author="twaritwaikar" +version="v3.1.1" +script="godot-git-plugin.gd" diff --git a/addons/godot-git-plugin/win64/libgit_plugin.windows.editor.x86_64.dll b/addons/godot-git-plugin/win64/libgit_plugin.windows.editor.x86_64.dll new file mode 100644 index 0000000..47bbb1d Binary files /dev/null and b/addons/godot-git-plugin/win64/libgit_plugin.windows.editor.x86_64.dll differ diff --git a/addons/godot-git-plugin/win64/libgit_plugin.windows.editor.x86_64.exp b/addons/godot-git-plugin/win64/libgit_plugin.windows.editor.x86_64.exp new file mode 100644 index 0000000..6c68d89 Binary files /dev/null and b/addons/godot-git-plugin/win64/libgit_plugin.windows.editor.x86_64.exp differ diff --git a/addons/godot-git-plugin/win64/libgit_plugin.windows.editor.x86_64.lib b/addons/godot-git-plugin/win64/libgit_plugin.windows.editor.x86_64.lib new file mode 100644 index 0000000..4537929 Binary files /dev/null and b/addons/godot-git-plugin/win64/libgit_plugin.windows.editor.x86_64.lib differ diff --git a/addons/resources_spreadsheet_view/LICENSE.md b/addons/resources_spreadsheet_view/LICENSE.md new file mode 100644 index 0000000..0d448fd --- /dev/null +++ b/addons/resources_spreadsheet_view/LICENSE.md @@ -0,0 +1,9 @@ +# MIT License + +Copyright 2022 Gennady "Don Tnowe" Krupenyov + +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. diff --git a/addons/resources_spreadsheet_view/editor_color_setter.gd b/addons/resources_spreadsheet_view/editor_color_setter.gd new file mode 100644 index 0000000..5c35111 --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_color_setter.gd @@ -0,0 +1,6 @@ +@tool +extends Control + + +func _ready(): + modulate = get_theme_color("accent_color", "Editor") diff --git a/addons/resources_spreadsheet_view/editor_color_setter.gd.uid b/addons/resources_spreadsheet_view/editor_color_setter.gd.uid new file mode 100644 index 0000000..2489b3b --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_color_setter.gd.uid @@ -0,0 +1 @@ +uid://b2h3pdbtg7cyr diff --git a/addons/resources_spreadsheet_view/editor_icon_button.gd b/addons/resources_spreadsheet_view/editor_icon_button.gd new file mode 100644 index 0000000..0259cb0 --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_icon_button.gd @@ -0,0 +1,12 @@ +@tool +extends Button + +@export var icon_name := "Node" : + set(v): + icon_name = v + if has_theme_icon(v, "EditorIcons"): + icon = get_theme_icon(v, "EditorIcons") + + +func _ready(): + self.icon_name = (icon_name) diff --git a/addons/resources_spreadsheet_view/editor_icon_button.gd.uid b/addons/resources_spreadsheet_view/editor_icon_button.gd.uid new file mode 100644 index 0000000..02ecae5 --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_icon_button.gd.uid @@ -0,0 +1 @@ +uid://dm52kewgqokey diff --git a/addons/resources_spreadsheet_view/editor_resource_array_picker.gd b/addons/resources_spreadsheet_view/editor_resource_array_picker.gd new file mode 100644 index 0000000..15be1ef --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_resource_array_picker.gd @@ -0,0 +1,69 @@ +@tool +extends EditorResourcePicker + +signal on_resources_dropped(resources : Array) + +var _prepared_for_drop := false +var _drop_hint_label : Label + + +func _ready(): + resource_changed.connect(_on_resource_changed) + _drop_hint_label = Label.new() + _drop_hint_label.text = "[Drop Here to Add!]" + _drop_hint_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _drop_hint_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + _drop_hint_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER + _drop_hint_label.hide() + add_child(_drop_hint_label) + + +func set_prepared_for_drop(state : bool): + for x in get_children(true): + if not x is Popup and (not x is Label): + x.visible = not state + + _drop_hint_label.visible = state + custom_minimum_size = size if state else Vector2.ZERO + _prepared_for_drop = state + + +func _can_drop_data(at_position: Vector2, data: Variant) -> bool: + var data_drop_type : StringName = data.get(&"type", &"") + if data_drop_type != &"files" or data_drop_type != &"resource": + return true + + set_prepared_for_drop(true) + return false + + +func _drop_data(at_position: Vector2, data: Variant): + var data_drop_type : StringName = data.get(&"type", &"") + var new_array : Array[Resource] = [] + if data_drop_type == &"files": + for x in data.files: + new_array.append(load(x)) + + if data_drop_type == &"resource": + new_array.append(data.resource) + + if new_array.size() == 0: + return + + edited_resource = new_array[0] + on_resources_dropped.emit(new_array) + + +func _input(event: InputEvent): + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: + if !event.pressed: + set_prepared_for_drop(false) + + if event is InputEventMouseMotion and not _prepared_for_drop: + # _can_drop_data() is only called when hovering over the picker. Items must be hidden before that. + if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and not get_global_rect().has_point(event.global_position): + set_prepared_for_drop(true) + + +func _on_resource_changed(new_resource : Resource): + on_resources_dropped.emit([new_resource]) diff --git a/addons/resources_spreadsheet_view/editor_resource_array_picker.gd.uid b/addons/resources_spreadsheet_view/editor_resource_array_picker.gd.uid new file mode 100644 index 0000000..7805f13 --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_resource_array_picker.gd.uid @@ -0,0 +1 @@ +uid://btboc28h8phls diff --git a/addons/resources_spreadsheet_view/editor_view.gd b/addons/resources_spreadsheet_view/editor_view.gd new file mode 100644 index 0000000..8886093 --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_view.gd @@ -0,0 +1,527 @@ +@tool +extends Control + +signal grid_updated() + +const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd") + +@onready var node_folder_path : LineEdit = $"HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer/Path" +@onready var node_recent_paths : OptionButton = $"HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer2/RecentPaths" +@onready var node_table_root : GridContainer = $"HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Scroll/MarginContainer/TableGrid" +@onready var node_columns : HBoxContainer = $"HeaderContentSplit/VBoxContainer/Columns/Columns" +@onready var node_page_manager : Control = $"HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages" +@onready var node_class_filter : Control = $"HeaderContentSplit/VBoxContainer/Search/Search/Class" + +@onready var _on_cell_gui_input : Callable = $"InputHandler"._on_cell_gui_input +@onready var _selection := $"SelectionManager" + +var editor_interface : Object +var editor_plugin : EditorPlugin + +var current_path := "" +var save_data_path : String = get_script().resource_path.get_base_dir() + "/saved_state.json" +var sorting_by := &"" +var sorting_reverse := false + +var columns : Array[StringName] = [] +var column_types : Array[int] = [] +var column_hints : Array[int] = [] +var column_hint_strings : Array[PackedStringArray] = [] +var rows := [] +var remembered_paths := {} +var remembered_paths_total_count := 0 +var table_functions_dict := {} + +var search_cond : Callable +var io : RefCounted + +var first_row := 0 +var last_row := 0 + + +func _ready(): + editor_interface.get_resource_filesystem().filesystem_changed.connect(_on_filesystem_changed) + if FileAccess.file_exists(save_data_path): + var file := FileAccess.open(save_data_path, FileAccess.READ) + var as_text := file.get_as_text() + var as_var := JSON.parse_string(as_text) + + node_recent_paths.load_paths(as_var.get(&"recent_paths", [])) + node_columns.column_properties = as_var.get(&"column_properties", {}) + table_functions_dict = as_var.get(&"table_functions", {}) + for x in $"HeaderContentSplit/VBoxContainer/Search/Search".get_children(): + if x.has_method(&"load_saved_functions"): + x.load_saved_functions(table_functions_dict) + + # Legacy compat: old hidden column format + var legacy_hidden_columns : Dictionary = as_var.get(&"hidden_columns", {}) + for k in legacy_hidden_columns: + for k2 in legacy_hidden_columns[k]: + node_columns.column_properties[k] = node_columns.column_properties.get(k, {}) + node_columns.column_properties[k][k2] = { &"visibility" : 0 } + + if node_recent_paths.recent_paths.size() >= 1: + display_folder(node_recent_paths.recent_paths[-1], &"resource_name", false, true) + + +func save_data(): + if ( + node_recent_paths.recent_paths.is_empty() + and node_columns.column_properties.is_empty() + and table_functions_dict.is_empty() + ): + return + + var file := FileAccess.open(save_data_path, FileAccess.WRITE) + file.store_string(JSON.stringify( + { + &"recent_paths" : node_recent_paths.recent_paths, + &"column_properties" : node_columns.column_properties, + &"table_functions" : table_functions_dict, + } + , " ")) + + +func _on_filesystem_changed(): + if current_path == "": + return + + var file_total_count := _get_file_count_recursive(current_path) + if file_total_count != remembered_paths_total_count: + refresh() + + else: + for k in remembered_paths: + if !is_instance_valid(remembered_paths[k]): + continue + + if remembered_paths[k].resource_path != k: + var res = remembered_paths[k] + remembered_paths.erase(k) + remembered_paths[res.resource_path] = res + refresh() + break + + +func _get_file_count_recursive(path : String) -> int: + var editor_fs : EditorFileSystem = editor_interface.get_resource_filesystem() + var path_dir := editor_fs.get_filesystem_path(path) + if !path_dir: return 0 + + var file_total_count := 0 + var folder_stack : Array[EditorFileSystemDirectory] = [path_dir] + while folder_stack.size() > 0: + path_dir = folder_stack.pop_back() + file_total_count += path_dir.get_file_count() + for i in path_dir.get_subdir_count(): + folder_stack.append(path_dir.get_subdir(i)) + + return file_total_count + + +func display_folder(folderpath : String, sort_by : StringName = "", sort_reverse : bool = false, force_rebuild : bool = false, is_echo : bool = false): + if folderpath == "": + # You wouldn't just wanna edit ALL resources in the project, that's a long time to load! + return + + if sort_by == "": + sort_by = &"resource_path" + + if folderpath.get_extension() == "": + folderpath = folderpath.trim_suffix("/") + "/" + + if (folderpath.ends_with(".tres") or folderpath.ends_with(".res")) and !(load(folderpath) is ResourceTablesImport): + folderpath = folderpath.get_base_dir() + "/" + + node_recent_paths.add_path_to_recent(folderpath) + node_folder_path.text = folderpath + + _load_resources_from_path(folderpath, sort_by, sort_reverse) + _update_visible_rows(force_rebuild or current_path != folderpath) + + current_path = folderpath + remembered_paths_total_count = _get_file_count_recursive(folderpath) + node_columns.update() + grid_updated.emit() + + $"HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Label".visible = rows.size() == 0 + $"HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Label".text = "No rows visible?\nThis might happen when sorting by a property that isn't here anymore.\nTry clicking a column header to sort again!\n\nIt's also possible that your Filter expression is filtering them out." + + +func display_resources(resource_array : Array): + if sorting_by == "": + sorting_by = &"resource_path" + + current_path = "" + node_recent_paths.select(-1) + rows = [] + for x in resource_array: + insert_row_sorted(x, rows, sorting_by, sorting_reverse) + + fill_property_data_many(rows) + _update_visible_rows() + + node_columns.update() + grid_updated.emit() + + +func refresh(force_rebuild : bool = true): + if current_path == "": + display_resources(rows) + + else: + display_folder(current_path, sorting_by, sorting_reverse, force_rebuild) + + +func _load_resources_from_path(path : String, sort_by : StringName, sort_reverse : bool): + if path.ends_with("/"): + io = ResourceTablesEditFormatTres.new() + + else: + var loaded := load(path) + if loaded is ResourceTablesImport: + io = loaded.view_script.new() + node_class_filter.hide() + + else: + io = ResourceTablesEditFormatTres.new() + + io.editor_view = self + remembered_paths.clear() + rows = io.import_from_path(path, insert_row_sorted, sort_by, sort_reverse) + + +func _update_visible_rows(force_rebuild : bool = true): + node_page_manager.update_page_count(rows) + if columns.size() == 0: + return + + if force_rebuild or columns != node_columns.columns: + for x in node_table_root.get_children(): + x.free() + + node_columns.columns = columns + + var cells_left_to_free : int = node_table_root.get_child_count() - (last_row - first_row) * columns.size() + while cells_left_to_free > 0: + node_table_root.get_child(0).free() + cells_left_to_free -= 1 + + var color_rows : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "color_rows") + for i in last_row - first_row: + _update_row(first_row + i, color_rows) + + +func fill_property_data(res : Resource): + columns.clear() + column_types.clear() + column_hints.clear() + column_hint_strings.clear() + var column_values := [] + var i := -1 + for x in res.get_property_list(): + if x[&"usage"] & PROPERTY_USAGE_EDITOR != 0 and x[&"name"] != "script": + i += 1 + columns.append(x[&"name"]) + column_types.append(x[&"type"]) + column_hints.append(x[&"hint"]) + column_hint_strings.append(x[&"hint_string"].split(",")) + column_values.append(io.get_value(res, columns[i])) + + _selection.initialize_editors(column_values, column_types, column_hints) + + +func fill_property_data_many(resources : Array): + node_class_filter.fill(resources) + + columns.clear() + column_types.clear() + column_hints.clear() + column_hint_strings.clear() + var column_values := [] + var i := -1 + var found_props := {} + for x in resources: + if x == null: continue + i += 1 + if not search_cond.is_null() and not search_cond.call(x, i): + continue + + if not node_class_filter.filter(x): + continue + + for y in x.get_property_list(): + found_props[y[&"name"]] = y + y[&"owner_object"] = x + + i = -1 + for x in found_props.values(): + if x[&"usage"] & PROPERTY_USAGE_EDITOR != 0 and x[&"name"] != "script": + i += 1 + columns.append(x[&"name"]) + column_types.append(x[&"type"]) + column_hints.append(x[&"hint"]) + column_hint_strings.append(x[&"hint_string"].split(",")) + column_values.append(io.get_value(x[&"owner_object"], columns[i])) + + _selection.initialize_editors(column_values, column_types, column_hints) + + +func insert_row_sorted(res : Resource, loaded_rows : Array, sort_by : StringName, sort_reverse : bool): + if not search_cond.is_null() and not search_cond.call(res, loaded_rows.size()): + return + + if not sort_by in res or not node_class_filter.filter(res): + return + + var sort_value = res[sort_by] + for i in loaded_rows.size(): + if sort_reverse == compare_values(sort_value, loaded_rows[i][sort_by]): + loaded_rows.insert(i, res) + return + + remembered_paths[res.resource_path] = res + loaded_rows.append(res) + + +func compare_values(a, b) -> bool: + if a == null or b == null: return b == null + if a is float or a is int: + return a > b + + if a is Color: + return a.h > b.h if a.h != b.h else a.v > b.v + + if a is Resource: + return a.resource_path > b.resource_path + + return str(a) > str(b) + + +func column_can_solo_open(column_index : int) -> bool: + return ( + column_types[column_index] == TYPE_OBJECT + or (column_types[column_index] == TYPE_ARRAY and column_hint_strings[column_index][0].begins_with("24")) + ) + + +func column_solo_open(column_index : int): + display_folder(current_path.trim_suffix("/") + "::" + columns[column_index]) + + +func _set_sorting(sort_by : StringName): + var sort_reverse : bool = !(sorting_by != sort_by or sorting_reverse) + sorting_reverse = sort_reverse + sorting_by = sort_by + refresh() + + +func _update_row(row_index : int, color_rows : bool = true): + var current_node : Control + var next_color := Color.WHITE + var column_editors : Array = _selection.column_editors + var shortened_path : String = rows[row_index].resource_path.substr(current_path.length()).trim_suffix(".tres").trim_suffix(".res") + for i in columns.size(): + if node_table_root.get_child_count() <= (row_index - first_row) * columns.size() + i: + current_node = column_editors[i].create_cell(self) + current_node.gui_input.connect(_on_cell_gui_input.bind(current_node)) + node_table_root.add_child(current_node) + + else: + current_node = node_table_root.get_child((row_index - first_row) * columns.size() + i) + current_node.tooltip_text = ( + columns[i].capitalize() + + "\n---\n" + + "Of " + shortened_path + ) + + if columns[i] in rows[row_index]: + current_node.mouse_filter = MOUSE_FILTER_STOP + current_node.modulate.a = 1.0 + + else: + # Empty cell, can't click, property doesn't exist. + current_node.mouse_filter = MOUSE_FILTER_IGNORE + current_node.modulate.a = 0.0 + continue + + if columns[i] == &"resource_path": + column_editors[i].set_value(current_node, shortened_path) + + else: + var cell_value = io.get_value(rows[row_index], columns[i]) + if cell_value != null or column_types[i] == TYPE_OBJECT: + column_editors[i].set_value(current_node, cell_value) + if color_rows and column_types[i] == TYPE_COLOR: + next_color = cell_value + + column_editors[i].set_color(current_node, next_color) + + +func get_selected_column() -> int: + return _selection.get_cell_column(_selection.edited_cells[0]) + + +func select_column(column_index : int): + _selection.deselect_all_cells() + _selection.select_cell(Vector2i(column_index, 0)) + _selection.select_cells_to(Vector2i(column_index, rows.size() - 1)) + + +func set_edited_cells_values_text(new_cell_values : Array): + var column_editor : Object = _selection.column_editors[get_selected_column()] + + # Duplicated here since if using text editing, edited_cells_text needs to modified + # but here, it would be converted from a String breaking editing + var new_cell_values_converted := new_cell_values.duplicate() + for i in new_cell_values.size(): + new_cell_values_converted[i] = column_editor.from_text(new_cell_values[i]) + + set_edited_cells_values(new_cell_values_converted) + for i in new_cell_values.size(): + var i_pos : Vector2i = _selection.edited_cells[i] + var update_cell : Control = _selection.get_cell_node_from_position(i_pos) + if update_cell == null: + continue + + column_editor.set_value(update_cell, new_cell_values[i]) + + +func set_edited_cells_values(new_cell_values : Array): + var edited_rows : Array = _selection.get_edited_rows() + var column : int = _selection.get_cell_column(_selection.edited_cells[0]) + var edited_cells_resources := _get_row_resources(edited_rows) + + editor_plugin.undo_redo.create_action("Set Cell Values") + editor_plugin.undo_redo.add_undo_method( + self, + &"_update_resources", + edited_cells_resources.duplicate(), + edited_rows.duplicate(), + column, + get_edited_cells_values() + ) + editor_plugin.undo_redo.add_undo_method( + _selection, + &"_update_selected_cells_text" + ) + editor_plugin.undo_redo.add_do_method( + self, + &"_update_resources", + edited_cells_resources.duplicate(), + edited_rows.duplicate(), + column, + new_cell_values.duplicate() + ) + editor_plugin.undo_redo.commit_action(true) + _selection._update_selected_cells_text() + + +func rename_row(row, new_name): + if !has_row_names(): return + + io.rename_row(row, new_name) + refresh() + + +func duplicate_selected_rows(new_name : String): + io.duplicate_rows(_get_row_resources(_selection.get_edited_rows()), new_name) + refresh() + + +func delete_selected_rows(): + io.delete_rows(_get_row_resources(_selection.get_edited_rows())) + refresh() + refresh.call_deferred() + + +func has_row_names(): + return io.has_row_names() + + +func get_last_selected_row(): + return rows[_selection.get_cell_row(_selection.edited_cells[-1])] + + +func get_edited_cells_values() -> Array: + var cells : Array = _selection.edited_cells.duplicate() + var column_index : int = _selection.get_cell_column(cells[0]) + var result := [] + result.resize(cells.size()) + for i in cells.size(): + result[i] = io.get_value(rows[_selection.get_cell_row(cells[i])], columns[column_index]) + + return result + + +func _update_resources(update_rows : Array, update_row_indices : Array[int], update_column : int, values : Array): + var column_editor : Object = _selection.column_editors[update_column] + for i in update_rows.size(): + var row := update_row_indices[i] + io.set_value( + update_rows[i], + columns[update_column], + values[i], + row + ) + var update_cell : Control = _selection.get_cell_node_from_position(Vector2i(update_column, row)) + if update_cell == null: + continue + + column_editor.set_value(update_cell, values[i]) + var row_script : Object = update_rows[i].get_script() + if row_script != null && row_script.is_tool(): + for column_i in columns.size(): + if column_i == update_column: + continue + + var update_cell_c : Control = _selection.get_cell_node_from_position(Vector2i(column_i, row)) + if columns[column_i] != &"resource_path": + _selection.column_editors[column_i].set_value(update_cell_c, update_rows[i].get(columns[column_i])) + + if values[i] == null: + continue + + if column_types[update_column] == TYPE_COLOR: + for j in columns.size() - update_column: + if j != 0 and column_types[j + update_column] == TYPE_COLOR: + break + + _selection.column_editors[j + update_column].set_color( + _selection.get_cell_node_from_position(Vector2i(update_column + j, row)), + values[i] + ) + + node_columns._update_column_sizes() + io.save_entries(rows, update_row_indices) + + +func _on_path_text_submitted(new_text : String = ""): + if new_text != "": + current_path = new_text + display_folder(new_text, "", false, true) + + else: + refresh() + + +func _on_FileDialog_dir_selected(dir : String): + node_folder_path.text = dir + display_folder(dir) + + +func _get_row_resources(row_indices) -> Array: + var arr := [] + arr.resize(row_indices.size()) + for i in arr.size(): + arr[i] = rows[row_indices[i]] + + return arr + + +func _on_File_pressed(): + node_folder_path.get_parent().get_parent().visible = !node_folder_path.get_parent().get_parent().visible + + +func _on_SearchProcess_pressed(): + $"HeaderContentSplit/VBoxContainer/Search".visible = !$"HeaderContentSplit/VBoxContainer/Search".visible diff --git a/addons/resources_spreadsheet_view/editor_view.gd.uid b/addons/resources_spreadsheet_view/editor_view.gd.uid new file mode 100644 index 0000000..3ec3be3 --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_view.gd.uid @@ -0,0 +1 @@ +uid://bv36hpm8lihns diff --git a/addons/resources_spreadsheet_view/editor_view.tscn b/addons/resources_spreadsheet_view/editor_view.tscn new file mode 100644 index 0000000..a102656 --- /dev/null +++ b/addons/resources_spreadsheet_view/editor_view.tscn @@ -0,0 +1,606 @@ +[gd_scene load_steps=33 format=3 uid="uid://5pic6fxx6et3"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_view.gd" id="1_wfx75"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_color_setter.gd" id="2_t2s7k"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="3_7ja2l"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/recent_paths.gd" id="4_umoob"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/expression_textfield.gd" id="5_faq75"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/table_pages.gd" id="5_ka2yn"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/class_filter.gd" id="6_2v7d5"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/column_header_manager.gd" id="6_emnmd"] +[ext_resource type="PackedScene" uid="uid://d1s6oihqedvo5" path="res://addons/resources_spreadsheet_view/main_screen/table_header.tscn" id="7_3dx0v"] +[ext_resource type="PackedScene" uid="uid://ddqak780cwwfj" path="res://addons/resources_spreadsheet_view/typed_editors/dock_enum_array.tscn" id="8_234wn"] +[ext_resource type="PackedScene" uid="uid://c3a2cip8ffccv" path="res://addons/resources_spreadsheet_view/typed_editors/dock_array.tscn" id="9_nts08"] +[ext_resource type="PackedScene" uid="uid://b3a3bo6cfyh5t" path="res://addons/resources_spreadsheet_view/typed_editors/dock_color.tscn" id="10_nsma2"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/frozen_columns.gd" id="10_vb62w"] +[ext_resource type="PackedScene" uid="uid://gtbf7b0wptv" path="res://addons/resources_spreadsheet_view/typed_editors/dock_number.tscn" id="11_q1ao4"] +[ext_resource type="PackedScene" uid="uid://rww3gpl052bn" path="res://addons/resources_spreadsheet_view/typed_editors/dock_texture.tscn" id="12_4kr6q"] +[ext_resource type="PackedScene" uid="uid://dhunxgcae6h1" path="res://addons/resources_spreadsheet_view/settings_grid.tscn" id="13_as1sh"] +[ext_resource type="PackedScene" uid="uid://p6x03dbvhnqw" path="res://addons/resources_spreadsheet_view/typed_editors/dock_dict.tscn" id="13_il556"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/input_handler.gd" id="14_2t57a"] +[ext_resource type="PackedScene" uid="uid://b413igx28kkvb" path="res://addons/resources_spreadsheet_view/import_export/import_export_dialog.tscn" id="14_3p12b"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/selection_manager.gd" id="15_mx6qn"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd" id="16_p7n52"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd" id="17_sofdw"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd" id="18_oeewr"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd" id="19_7x44x"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd" id="19_oeuko"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd" id="20_swsbn"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd" id="21_58wf8"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd" id="22_bni8r"] +[ext_resource type="PackedScene" uid="uid://b51hnttsie7k5" path="res://addons/resources_spreadsheet_view/main_screen/selection_actions.tscn" id="23_m53sx"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd" id="28_a0j2e"] + +[sub_resource type="Gradient" id="Gradient_8kp6w"] +offsets = PackedFloat32Array(0, 0.995413, 1) +colors = PackedColorArray(1, 1, 1, 0.490196, 1, 1, 1, 0.0458716, 1, 1, 1, 0) + +[sub_resource type="GradientTexture2D" id="GradientTexture2D_18il8"] +gradient = SubResource("Gradient_8kp6w") + +[node name="Control" type="MarginContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +focus_neighbor_left = NodePath(".") +focus_neighbor_top = NodePath(".") +focus_neighbor_right = NodePath(".") +focus_neighbor_bottom = NodePath(".") +focus_next = NodePath(".") +focus_previous = NodePath(".") +focus_mode = 2 +theme_override_constants/margin_left = 3 +theme_override_constants/margin_right = 3 +theme_override_constants/margin_bottom = 5 +script = ExtResource("1_wfx75") +metadata/_edit_lock_ = true + +[node name="HeaderContentSplit" type="VBoxContainer" parent="."] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="HeaderContentSplit"] +layout_mode = 2 + +[node name="MenuStrip" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer"] +layout_mode = 2 + +[node name="File" type="Button" parent="HeaderContentSplit/VBoxContainer/MenuStrip"] +layout_mode = 2 +tooltip_text = "Settings" +focus_mode = 0 +toggle_mode = true +button_pressed = true +text = "File" +flat = true + +[node name="SearchProcess" type="Button" parent="HeaderContentSplit/VBoxContainer/MenuStrip"] +layout_mode = 2 +tooltip_text = "Settings" +focus_mode = 0 +toggle_mode = true +button_pressed = true +text = "Filter/Process" +flat = true + +[node name="VisibleCols" type="MenuButton" parent="HeaderContentSplit/VBoxContainer/MenuStrip"] +layout_mode = 2 +text = "Shown Columns" + +[node name="VSeparator" type="Control" parent="HeaderContentSplit/VBoxContainer/MenuStrip"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Settings" type="Button" parent="HeaderContentSplit/VBoxContainer/MenuStrip"] +layout_mode = 2 +tooltip_text = "Settings" +focus_mode = 0 +text = "Settings" +flat = true + +[node name="VSeparator2" type="VSeparator" parent="HeaderContentSplit/VBoxContainer/MenuStrip"] +layout_mode = 2 + +[node name="Info" type="Button" parent="HeaderContentSplit/VBoxContainer/MenuStrip"] +layout_mode = 2 +focus_mode = 0 +text = "About" +flat = true + +[node name="HBoxContainer" type="HSplitContainer" parent="HeaderContentSplit/VBoxContainer"] +layout_mode = 2 +split_offset = -249 + +[node name="HBoxContainer" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_constants/separation = 0 + +[node name="ColorRect4" type="ColorRect" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"] +modulate = Color(0, 0, 0, 1) +custom_minimum_size = Vector2(6, 18) +layout_mode = 2 +script = ExtResource("2_t2s7k") + +[node name="TextureRect" type="TextureRect" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer/ColorRect4"] +layout_mode = 1 +anchors_preset = 11 +anchor_left = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = 48.0 +grow_horizontal = 0 +grow_vertical = 2 +texture = SubResource("GradientTexture2D_18il8") +expand_mode = 1 + +[node name="ColorRect3" type="Control" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"] +custom_minimum_size = Vector2(2, 0) +layout_mode = 2 + +[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Resource Folder:" + +[node name="Path" type="LineEdit" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +caret_blink = true + +[node name="SelectDir" type="Button" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Open Folder" +script = ExtResource("3_7ja2l") +icon_name = "Folder" + +[node name="DeletePath" type="Button" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Remove Path from Recent" +script = ExtResource("3_7ja2l") +icon_name = "Remove" + +[node name="HBoxContainer2" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="Label2" type="Label" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer2"] +layout_mode = 2 +text = "Open Recent:" + +[node name="RecentPaths" type="OptionButton" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer2"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +clip_text = true +fit_to_longest_item = false +script = ExtResource("4_umoob") + +[node name="ImportExport" type="Button" parent="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer2"] +layout_mode = 2 +text = "Import/Export CSV..." +script = ExtResource("3_7ja2l") +icon_name = "TextFile" + +[node name="Search" type="VBoxContainer" parent="HeaderContentSplit/VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 0 + +[node name="HBoxContainer" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/Search"] +layout_mode = 2 + +[node name="ColorRect4" type="ColorRect" parent="HeaderContentSplit/VBoxContainer/Search/HBoxContainer"] +modulate = Color(0, 0, 0, 1) +custom_minimum_size = Vector2(6, 18) +layout_mode = 2 +size_flags_vertical = 5 +script = ExtResource("2_t2s7k") + +[node name="TextureRect" type="TextureRect" parent="HeaderContentSplit/VBoxContainer/Search/HBoxContainer/ColorRect4"] +layout_mode = 1 +anchors_preset = 11 +anchor_left = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = 48.0 +grow_horizontal = 0 +grow_vertical = 2 +texture = SubResource("GradientTexture2D_18il8") +expand_mode = 1 + +[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/HBoxContainer"] +layout_mode = 2 +text = "GDScript Filter and Process" + +[node name="HSeparator" type="HSeparator" parent="HeaderContentSplit/VBoxContainer/Search/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Search" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/Search"] +layout_mode = 2 + +[node name="ColorRect2" type="ColorRect" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +modulate = Color(0, 0, 0, 1) +custom_minimum_size = Vector2(6, 18) +layout_mode = 2 +size_flags_vertical = 5 +script = ExtResource("2_t2s7k") + +[node name="TextureRect" type="TextureRect" parent="HeaderContentSplit/VBoxContainer/Search/Search/ColorRect2"] +layout_mode = 1 +anchors_preset = 11 +anchor_left = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = 48.0 +grow_horizontal = 0 +grow_vertical = 2 +texture = SubResource("GradientTexture2D_18il8") +expand_mode = 1 + +[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 +text = "Condition:" + +[node name="Label2" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 +tooltip_text = "Enter an expression. The table only show rows where the expression returns `true`. + +You can use `res.` to get a property, and `index` to get row number. Hit ENTER to run the search. + +Try out these: +- (res.number_property > 0 and res.number_property < 100) +- (res.text_property != \\\"\\\") +- (\\\"a\\\" in res.text_property) +- (index < 5)" +mouse_filter = 0 +mouse_default_cursor_shape = 16 +text = "(?)" + +[node name="Filter" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 +size_flags_horizontal = 3 +script = ExtResource("5_faq75") +editor_view_path = NodePath("../../../../..") +title = "func f(res : Resource, index : int):" +default_text = "true" +default_text_ml = "return true" +function_save_key = "filter" + +[node name="VSeparator" type="VSeparator" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 + +[node name="Class" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 +script = ExtResource("6_2v7d5") + +[node name="Label5" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/Search/Class"] +layout_mode = 2 +text = "Class:" + +[node name="Class" type="OptionButton" parent="HeaderContentSplit/VBoxContainer/Search/Search/Class"] +layout_mode = 2 +clip_text = true +fit_to_longest_item = false + +[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/Search/Class"] +layout_mode = 2 +text = "Sub:" + +[node name="Subclasses" type="CheckBox" parent="HeaderContentSplit/VBoxContainer/Search/Search/Class"] +layout_mode = 2 +tooltip_text = "Include Subclasses" +button_pressed = true + +[node name="VSeparator2" type="VSeparator" parent="HeaderContentSplit/VBoxContainer/Search/Search/Class"] +layout_mode = 2 + +[node name="Label3" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 +text = "Process:" + +[node name="Label4" type="Label" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 +tooltip_text = "Enter an expression. The values in selected cells will be replaced with calculated new values. + +You can use `value` to get the cell's value, `res.` to get a property, `row_index` to get row number +and `cell_index` to get the cell's selection order. Hit ENTER to run the search. + +These are some valid expressions: +- (res.property1 + res.property2) +- (res.property1.replace(\\\"old_string\\\", \\\"new_string\\\")) +- (load(\\\"res://path/to_resource.tres\\\")) + +Don't forget quotation marks on strings and str() on non-strings." +mouse_filter = 0 +mouse_default_cursor_shape = 16 +text = "(?)" + +[node name="Process" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/Search/Search"] +layout_mode = 2 +size_flags_horizontal = 3 +script = ExtResource("5_faq75") +editor_view_path = NodePath("../../../../..") +mode = 1 +title = "func f(value : Var, res : Resource, all_res : Array[Resource], row_index : int):" +default_text = "value" +default_text_ml = "return value" +function_save_key = "process" + +[node name="HBoxContainer3" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3"] +layout_mode = 2 +text = "Grid" + +[node name="Refresh" type="Button" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3"] +layout_mode = 2 +tooltip_text = "Refresh" +script = ExtResource("3_7ja2l") +icon_name = "Loop" + +[node name="Pages" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3"] +layout_mode = 2 +size_flags_horizontal = 3 +script = ExtResource("5_ka2yn") + +[node name="Label" type="Label" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages"] +layout_mode = 2 +text = "Page:" + +[node name="Scroll" type="ScrollContainer" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages"] +layout_mode = 2 +size_flags_horizontal = 3 +follow_focus = true +vertical_scroll_mode = 0 + +[node name="Pagelist" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages/Scroll"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Label2" type="Label" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages"] +layout_mode = 2 +text = "Rows per page:" + +[node name="LineEdit" type="SpinBox" parent="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages"] +layout_mode = 2 +size_flags_vertical = 4 +min_value = 2.0 +max_value = 300.0 +value = 50.0 + +[node name="Sep" type="Control" parent="HeaderContentSplit/VBoxContainer"] +layout_mode = 2 + +[node name="Columns" type="Control" parent="HeaderContentSplit/VBoxContainer"] +clip_contents = true +layout_mode = 2 + +[node name="Columns" type="HBoxContainer" parent="HeaderContentSplit/VBoxContainer/Columns"] +layout_mode = 0 +theme_override_constants/separation = 0 +script = ExtResource("6_emnmd") +table_header_scene = ExtResource("7_3dx0v") + +[node name="Sep2" type="Control" parent="HeaderContentSplit/VBoxContainer"] +visible = false +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="HeaderContentSplit"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +mouse_filter = 2 + +[node name="FooterContentSplit" type="VBoxContainer" parent="HeaderContentSplit/MarginContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Panel" type="MarginContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit"] +layout_mode = 2 +size_flags_vertical = 3 +mouse_filter = 2 + +[node name="Panel" type="Panel" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel"] +layout_mode = 2 + +[node name="Scroll" type="ScrollContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="MarginContainer" type="MarginContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Scroll"] +layout_mode = 2 + +[node name="TableGrid" type="GridContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Scroll/MarginContainer"] +layout_mode = 2 +theme_override_constants/h_separation = 0 +theme_override_constants/v_separation = 0 + +[node name="Label" type="Label" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel"] +self_modulate = Color(1, 1, 1, 0.498039) +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +text = "No folder selected! +Please select a folder to edit using the text field or Open button above. + +Then, Shift+Click or Ctrl+Click cells to edit them using the keyboard, +Inspector dock or this screen's bottom panels. + +To find out keybindings available, open the \"About\" menu." +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="FrozenColumns" type="Control" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel"] +clip_contents = true +layout_mode = 2 +mouse_filter = 2 + +[node name="FrozenColumns" type="ColorRect" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/FrozenColumns"] +layout_mode = 1 +size_flags_horizontal = 0 +mouse_filter = 2 +script = ExtResource("10_vb62w") + +[node name="Footer" type="VBoxContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit"] +layout_mode = 2 + +[node name="PropertyEditors" type="VBoxContainer" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer"] +unique_name_in_owner = true +layout_mode = 2 + +[node name="EditEnumArray" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/PropertyEditors" instance=ExtResource("8_234wn")] +visible = false +layout_mode = 2 + +[node name="EditArray" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/PropertyEditors" instance=ExtResource("9_nts08")] +visible = false +layout_mode = 2 + +[node name="EditDict" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/PropertyEditors" instance=ExtResource("13_il556")] +visible = false +layout_mode = 2 + +[node name="EditColor" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/PropertyEditors" instance=ExtResource("10_nsma2")] +visible = false +layout_mode = 2 + +[node name="EditNumber" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/PropertyEditors" instance=ExtResource("11_q1ao4")] +visible = false +layout_mode = 2 + +[node name="EditTexture" parent="HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/PropertyEditors" instance=ExtResource("12_4kr6q")] +visible = false +layout_mode = 2 + +[node name="Control" type="Control" parent="."] +layout_mode = 2 +mouse_filter = 2 +metadata/_edit_lock_ = true + +[node name="FileDialog" type="FileDialog" parent="Control"] +title = "Open" +size = Vector2i(800, 500) +min_size = Vector2i(800, 400) +ok_button_text = "Open" +mode_overrides_title = false +file_mode = 3 +filters = PackedStringArray("*.tres", "*.res") + +[node name="FileDialogText" type="FileDialog" parent="Control"] +title = "Open or Create Text File" +size = Vector2i(800, 500) +min_size = Vector2i(800, 400) +ok_button_text = "Open" +mode_overrides_title = false +file_mode = 3 +filters = PackedStringArray("*.csv") + +[node name="Info" type="AcceptDialog" parent="Control"] +title = "About" +size = Vector2i(800, 500) + +[node name="MarginContainer" type="MarginContainer" parent="Control/Info"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 8.0 +offset_top = 8.0 +offset_right = -8.0 +offset_bottom = -49.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="Panel" type="Panel" parent="Control/Info/MarginContainer"] +layout_mode = 2 + +[node name="RichTextLabel" type="RichTextLabel" parent="Control/Info/MarginContainer"] +layout_mode = 2 +bbcode_enabled = true +text = "Edit Resources as Table 2 + +\"Welp, it is what it sounds like!\" + +Possible inputs: +- Ctrl + Click / Cmd + Click - Select multiple cells in one column +- Shift + Click - Select all cells between A and B in one column +- Up / Down / Shift+Tab / Tab - move cell selection up/down/left/right + +- Left/Right - Move cursor along cell text +- Backspace/Delete - Erase text Left / Right from cursor +- Home/End - Move cursor to start/end of cell +- Ctrl + / Cmd + - Move through / Erase whole word + +- Ctrl/Cmd + C/V - Copy cells / Paste text into cells +- Ctrl/Cmd + (Shift) + Z - The Savior +If clipboard contains as many lines as there are cells selected, each line is pasted into a separate cell. + +Made by Don Tnowe. 2022. +https://twitter.com/don_tnowe +Issues and contribution: +https://github.com/don-tnowe/godot-resources-as-sheets-plugin" + +[node name="Settings" type="AcceptDialog" parent="Control"] +title = "Settings" +size = Vector2i(500, 300) +min_size = Vector2i(500, 300) + +[node name="Settings" parent="Control/Settings" instance=ExtResource("13_as1sh")] + +[node name="ImportExport" type="Window" parent="Control"] +process_mode = 3 +initial_position = 4 +size = Vector2i(600, 400) +visible = false +transient = true +exclusive = true +min_size = Vector2i(600, 400) + +[node name="ImportExport" parent="Control/ImportExport" instance=ExtResource("14_3p12b")] + +[node name="SelectionActions" parent="Control" instance=ExtResource("23_m53sx")] +visible = false +layout_mode = 2 +offset_left = -506.0 +offset_top = 65.0 +offset_right = -426.0 +offset_bottom = 117.0 + +[node name="InputHandler" type="Node" parent="."] +script = ExtResource("14_2t57a") + +[node name="SelectionManager" type="Control" parent="."] +layout_mode = 2 +mouse_filter = 2 +script = ExtResource("15_mx6qn") +cell_editor_classes = Array[Script]([ExtResource("16_p7n52"), ExtResource("19_oeuko"), ExtResource("17_sofdw"), ExtResource("18_oeewr"), ExtResource("19_7x44x"), ExtResource("20_swsbn"), ExtResource("21_58wf8"), ExtResource("28_a0j2e"), ExtResource("22_bni8r")]) +metadata/_edit_lock_ = true + +[connection signal="grid_updated" from="." to="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages" method="_on_grid_updated"] +[connection signal="grid_updated" from="." to="HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/FrozenColumns/FrozenColumns" method="_on_grid_updated"] +[connection signal="gui_input" from="." to="InputHandler" method="_gui_input"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/MenuStrip/File" to="." method="_on_File_pressed"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/MenuStrip/SearchProcess" to="." method="_on_SearchProcess_pressed"] +[connection signal="about_to_popup" from="HeaderContentSplit/VBoxContainer/MenuStrip/VisibleCols" to="HeaderContentSplit/VBoxContainer/Columns/Columns" method="_on_visible_cols_about_to_popup"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/MenuStrip/Settings" to="Control/Settings" method="popup_centered"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/MenuStrip/Info" to="Control/Info" method="popup_centered"] +[connection signal="text_submitted" from="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer/Path" to="." method="_on_path_text_submitted"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer/SelectDir" to="Control/FileDialog" method="popup_centered"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer/DeletePath" to="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer2/RecentPaths" method="remove_selected_path_from_recent"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/HBoxContainer/HBoxContainer2/ImportExport" to="Control/FileDialogText" method="popup_centered"] +[connection signal="pressed" from="HeaderContentSplit/VBoxContainer/HBoxContainer3/Refresh" to="." method="_on_path_text_submitted"] +[connection signal="value_changed" from="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages/LineEdit" to="HeaderContentSplit/VBoxContainer/HBoxContainer3/Pages" method="_on_LineEdit_value_changed"] +[connection signal="dir_selected" from="Control/FileDialog" to="." method="_on_FileDialog_dir_selected"] +[connection signal="file_selected" from="Control/FileDialog" to="." method="_on_FileDialog_dir_selected"] +[connection signal="dir_selected" from="Control/FileDialogText" to="Control/ImportExport/ImportExport" method="_on_file_selected"] +[connection signal="file_selected" from="Control/FileDialogText" to="Control/ImportExport/ImportExport" method="_on_file_selected"] +[connection signal="files_selected" from="Control/FileDialogText" to="Control/ImportExport/ImportExport" method="_on_files_selected"] +[connection signal="close_requested" from="Control/ImportExport" to="Control/ImportExport" method="hide"] +[connection signal="cells_rightclicked" from="SelectionManager" to="Control/SelectionActions" method="_on_grid_cells_rightclicked"] +[connection signal="cells_selected" from="SelectionManager" to="Control/SelectionActions" method="_on_grid_cells_selected"] diff --git a/addons/resources_spreadsheet_view/import_export/formats_edit/edit_base.gd b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_base.gd new file mode 100644 index 0000000..ff18907 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_base.gd @@ -0,0 +1,36 @@ +class_name ResourceTablesEditFormat +extends RefCounted + +var editor_view : Control + +## Override to define reading behaviour. +func get_value(entry, key : String): + pass + +## Override to define writing behaviour. This is NOT supposed to save - use `save_entries`. +func set_value(entry, key : String, value, index : int): + pass + +## Override to define how the data gets saved. +func save_entries(all_entries : Array, indices : Array): + pass + +## Override to allow editing rows from the Inspector. +func create_resource(entry) -> Resource: + return Resource.new() + +## Override to define duplication behaviour. `name_input` should be a suffix if multiple entries, and full name if one. +func duplicate_rows(rows : Array, name_input : String): + pass + +## Override to define removal behaviour. +func delete_rows(rows : Array): + pass + +## Override with `return true` if `resource_path` is defined and the Rename butoon should show. +func has_row_names(): + return false + +## Override to define import behaviour. Must return the `rows` value for the editor view. +func import_from_path(folderpath : String, insert_func : Callable, sort_by : String, sort_reverse : bool = false) -> Array: + return [] diff --git a/addons/resources_spreadsheet_view/import_export/formats_edit/edit_base.gd.uid b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_base.gd.uid new file mode 100644 index 0000000..c8dab80 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_base.gd.uid @@ -0,0 +1 @@ +uid://dbsk36h1hhs0r diff --git a/addons/resources_spreadsheet_view/import_export/formats_edit/edit_csv.gd b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_csv.gd new file mode 100644 index 0000000..96fb2f5 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_csv.gd @@ -0,0 +1,88 @@ +class_name ResourceTablesEditFormatCsv +extends ResourceTablesEditFormatTres + +var import_data : ResourceTablesImport +var csv_rows := [] +var resource_original_positions := {} + + +func get_value(entry, key : String): + return entry.get(key) + + +func set_value(entry, key : String, value, index : int): + entry.set(key, value) + csv_rows[resource_original_positions[entry]] = import_data.resource_to_strings(entry) + + +func save_entries(all_entries : Array, indices : Array, repeat : bool = true): + if timer == null or timer.time_left <= 0.0: + var space_after_delimiter := import_data.delimeter.ends_with(" ") + var file := FileAccess.open(import_data.edited_path, FileAccess.WRITE) + for x in csv_rows: + if space_after_delimiter: + for i in x.size(): + if i == 0: continue + x[i] = " " + x[i] + + file.store_csv_line(x, import_data.delimeter[0]) + + if repeat: + timer = editor_view.get_tree().create_timer(3.0) + timer.timeout.connect(save_entries.bind(all_entries, indices, false)) + + +func create_resource(entry) -> Resource: + return entry + + +func duplicate_rows(rows : Array, name_input : String): + for x in rows: + var new_res = x.duplicate() + var index : int = resource_original_positions[x] + csv_rows.insert(index, import_data.resource_to_strings(new_res)) + _bump_row_indices(index + 1, 1) + resource_original_positions[new_res] = index + 1 + + save_entries([], []) + + +func delete_rows(rows): + for x in rows: + var index : int = resource_original_positions[x] + csv_rows.remove_at(index) + _bump_row_indices(index, -1) + resource_original_positions.erase(x) + + save_entries([], []) + + +func has_row_names(): + return false + + +func _bump_row_indices(from : int, increment : int = 1): + for k in resource_original_positions: + if resource_original_positions[k] >= from: + resource_original_positions[k] += increment + + +func import_from_path(path : String, insert_func : Callable, sort_by : String, sort_reverse : bool = false) -> Array: + import_data = load(path) + var file := FileAccess.open(import_data.edited_path, FileAccess.READ) + csv_rows = ResourceTablesImportFormatCsv.import_as_arrays(import_data) + + var rows := [] + var res : Resource + resource_original_positions.clear() + for i in csv_rows.size(): + if import_data.remove_first_row and i == 0: + continue + + res = import_data.strings_to_resource(csv_rows[i], "") + res.resource_path = "" + insert_func.call(res, rows, sort_by, sort_reverse) + resource_original_positions[res] = i + + editor_view.fill_property_data(rows[0]) + return rows \ No newline at end of file diff --git a/addons/resources_spreadsheet_view/import_export/formats_edit/edit_csv.gd.uid b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_csv.gd.uid new file mode 100644 index 0000000..b10979d --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_csv.gd.uid @@ -0,0 +1 @@ +uid://cic06or8r4lwu diff --git a/addons/resources_spreadsheet_view/import_export/formats_edit/edit_tres.gd b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_tres.gd new file mode 100644 index 0000000..116adc5 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_tres.gd @@ -0,0 +1,119 @@ +class_name ResourceTablesEditFormatTres +extends ResourceTablesEditFormat + +var timer : SceneTreeTimer + + +func get_value(entry, key : String): + return entry[key] + + +func set_value(entry, key : String, value, index : int): + entry[key] = value + + +func save_entries(all_entries : Array, indices : Array, repeat : bool = true): + # No need to save. Resources are saved with Ctrl+S + # (likely because plugin.edit_resource is called to show inspector) + return + + +func create_resource(entry) -> Resource: + return entry + + +func duplicate_rows(rows : Array, name_input : String): + if rows.size() == 1: + var new_row = rows[0].duplicate() + var res_extension := ".res" if rows[0].resource_path.ends_with(".res") else ".tres" + new_row.resource_path = rows[0].resource_path.get_base_dir() + "/" + name_input + res_extension + ResourceSaver.save(new_row) + return + + var new_row + for x in rows: + new_row = x.duplicate() + var res_extension := ".res" if x.resource_path.ends_with(".res") else ".tres" + new_row.resource_path = x.resource_path.get_basename() + name_input + res_extension + ResourceSaver.save(new_row) + + +func rename_row(row, new_name : String): + var new_row = row + DirAccess.open("res://").remove(row.resource_path) + var res_extension := ".res" if row.resource_path.ends_with(".res") else ".tres" + new_row.resource_path = row.resource_path.get_base_dir() + "/" + new_name + res_extension + ResourceSaver.save(new_row) + + +func delete_rows(rows): + for x in rows: + DirAccess.open("res://").remove(x.resource_path) + + +func has_row_names(): + return true + + +func import_from_path(folderpath : String, insert_func : Callable, sort_by : String, sort_reverse : bool = false) -> Array: + var solo_property := "" + var solo_property_split : Array[String] = [] + if folderpath.contains("::"): + var found_at := folderpath.find("::") + solo_property = folderpath.substr(found_at + "::".length()).trim_suffix("/") + folderpath = folderpath.left(found_at) + for x in solo_property.split("::"): + solo_property_split.append(x) + + var rows := [] + var dir := DirAccess.open(folderpath) + if dir == null: return [] + + var file_stack : Array[String] = [] + var folder_stack : Array[String] = [folderpath] + + while folder_stack.size() > 0: + folderpath = folder_stack.pop_back() + + for x in DirAccess.get_files_at(folderpath): + file_stack.append(folderpath.path_join(x)) + + for x in DirAccess.get_directories_at(folderpath): + folder_stack.append(folderpath.path_join(x)) + + var loaded_res_unique := {} + for x in file_stack: + if !x.ends_with(".tres") and !x.ends_with(".res"): + continue + + if solo_property.is_empty(): + loaded_res_unique[load(x)] = true + + else: + _append_soloed_property(load(x), loaded_res_unique, solo_property_split) + + for x in loaded_res_unique.keys(): + if x == null: continue + insert_func.call(x, rows, sort_by, sort_reverse) + + editor_view.fill_property_data_many(loaded_res_unique.keys()) + return rows + + +func _append_soloed_property(current_res : Resource, result : Dictionary, solo_property_split : Array[String], solo_property_split_idx : int = -solo_property_split.size()): + var soloed_value = current_res[solo_property_split[solo_property_split_idx]] + if solo_property_split_idx == -1: + if soloed_value is Resource: + result[soloed_value] = true + + elif soloed_value is Array: + for x in soloed_value: + result[x] = true + + else: + if soloed_value is Resource: + _append_soloed_property(soloed_value, result, solo_property_split, solo_property_split_idx + 1) + + elif soloed_value is Array: + for x in soloed_value: + _append_soloed_property(x, result, solo_property_split, solo_property_split_idx + 1) \ No newline at end of file diff --git a/addons/resources_spreadsheet_view/import_export/formats_edit/edit_tres.gd.uid b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_tres.gd.uid new file mode 100644 index 0000000..43d93b3 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_edit/edit_tres.gd.uid @@ -0,0 +1 @@ +uid://b1eik1nl2b4h8 diff --git a/addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd b/addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd new file mode 100644 index 0000000..b407a55 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd @@ -0,0 +1,32 @@ +class_name ResourceTablesExportFormatCsv +extends RefCounted + + +static func can_edit_path(path : String): + return path.ends_with(".csv") + + +static func export_to_file(entries_array : Array, column_names : Array, into_path : String, import_data : ResourceTablesImport): + var file := FileAccess.open(into_path, FileAccess.WRITE) + + var line := PackedStringArray() + var space_after_delimiter := import_data.delimeter.ends_with(" ") + import_data.prop_names = column_names + import_data.prop_types = import_data.get_resource_property_types(entries_array[0], column_names) + import_data.resource_path = "" + line.resize(column_names.size()) + if import_data.remove_first_row: + for j in column_names.size(): + line[j] = String(column_names[j]) + if space_after_delimiter and j != 0: + line[j] = " " + line[j] + + file.store_csv_line(line, import_data.delimeter[0]) + + for i in entries_array.size(): + for j in column_names.size(): + line[j] = import_data.property_to_string((entries_array[i].get(column_names[j])), j) + if space_after_delimiter and j != 0: + line[j] = " " + line[j] + + file.store_csv_line(line, import_data.delimeter[0]) \ No newline at end of file diff --git a/addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd.uid b/addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd.uid new file mode 100644 index 0000000..20c980a --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd.uid @@ -0,0 +1 @@ +uid://cayugebl7vvsw diff --git a/addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd b/addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd new file mode 100644 index 0000000..6a3ad2f --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd @@ -0,0 +1,57 @@ +class_name ResourceTablesImportFormatCsv +extends RefCounted + + +static func can_edit_path(path : String): + return path.ends_with(".csv") + + +static func get_properties(entries, import_data): + return Array(entries[0]) + + +static func import_as_arrays(import_data) -> Array: + var file := FileAccess.open(import_data.edited_path, FileAccess.READ) + + import_data.delimeter = ";" + var text_lines : Array[PackedStringArray] = [file.get_line().split(import_data.delimeter)] + var space_after_delimeter := false + var line := text_lines[0] + if line.size() == 0: + return [] + + if line.size() == 1: + import_data.delimeter = "," + line = line[0].split(import_data.delimeter) + text_lines[0] = line + if line.size() <= 1: + return [] + + if line[1].begins_with(" "): + for i in line.size(): + line[i] = line[i].trim_prefix(" ") + + text_lines[0] = line + space_after_delimeter = true + import_data.delimeter += " " + + while !file.eof_reached(): + line = file.get_csv_line(import_data.delimeter[0]) + if space_after_delimeter: + for i in line.size(): + line[i] = line[i].trim_prefix(" ") + + if line.size() == text_lines[0].size(): + text_lines.append(line) + + elif line.size() != 1: + line.resize(text_lines[0].size()) + text_lines.append(line) + + var entries := [] + entries.resize(text_lines.size()) + + for i in entries.size(): + entries[i] = text_lines[i] + + return entries diff --git a/addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd.uid b/addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd.uid new file mode 100644 index 0000000..48bc9e6 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd.uid @@ -0,0 +1 @@ +uid://ccm0dyv7gtek3 diff --git a/addons/resources_spreadsheet_view/import_export/import_export_dialog.gd b/addons/resources_spreadsheet_view/import_export/import_export_dialog.gd new file mode 100644 index 0000000..6688431 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/import_export_dialog.gd @@ -0,0 +1,241 @@ +@tool +extends Control + +@export var prop_list_item_scene : PackedScene +@export var formats_export : Array[Script] +@export var formats_import : Array[Script] + +@onready var editor_view := $"../../.." +@onready var filename_options := $"Import/Margins/Scroll/Box/Grid/UseAsFilename" +@onready var classname_field := $"Import/Margins/Scroll/Box/Grid/Classname" +@onready var script_path_field := $"Import/Margins/Scroll/Box/Grid/HBoxContainer/LineEdit" +@onready var prop_list := $"Import/Margins/Scroll/Box" +@onready var format_settings := $"Import/Margins/Scroll/Box/StyleSettingsI" +@onready var file_dialog_use_script: FileDialog = $"Import/Margins/Scroll/Box/Grid/HBoxContainer/FileDialog" + +var format_extension := ".csv" +var entries := [] + +var import_data : ResourceTablesImport + + +func _ready(): + hide() + show() + if get_parent().get("size"): + get_parent().size = Vector2(600, 400) + + file_dialog_use_script.file_selected.connect(_on_file_dialog_file_selected) + + +func _on_file_selected(path : String): + if !FileAccess.file_exists(path): + if path.get_extension() != "": + # Path is a file path: replace extension + path = path.get_basename() + ".csv" + + else: + # Path is a directory: add filename, add extension + path = path.path_join(editor_view.current_path.trim_suffix("/").get_file()) + ".csv" + + FileAccess.open(path, FileAccess.WRITE) + + import_data = null + for x in DirAccess.get_files_at(path.get_base_dir()): + if !x.ends_with(".tres") and !x.ends_with(".res"): + continue + + var found_res := load(path.get_base_dir().path_join(x)) + if !(found_res is ResourceTablesImport): + continue + + _import_settings_from_settings_file(found_res, path) + break + + if import_data == null: + _create_new_settings_file(path) + + _create_prop_editors() + $"Import/Margins/Scroll/Box/StyleSettingsI"._send_signal() + + if editor_view.rows.size() > 0: + var using_script = editor_view.rows[0].get_script() + if using_script != null: + script_path_field.text = using_script.resource_path + + await get_tree().process_frame + get_parent().popup_centered() + await get_tree().process_frame + get_parent().min_size = get_combined_minimum_size() + position = Vector2.ZERO + size = get_parent().size + + +func _on_files_selected(paths : PackedStringArray): + _on_file_selected(paths[0]) + + +func _import_settings_from_settings_file(settings_file : ResourceTablesImport, textfile_path : String): + import_data = settings_file + + filename_options.clear() + for i in import_data.prop_names.size(): + filename_options.add_item(import_data.prop_names[i], i) + + if import_data.new_script != null: + classname_field.text = import_data.new_script.get_global_name() + script_path_field.text = settings_file.new_script.resource_path + + format_settings.set_format_array(import_data.enum_format) + for format_x in formats_import: + var new_importer = format_x.new() + if new_importer.can_edit_path(textfile_path): + entries = format_x.new().import_as_arrays(import_data) + break + + +func _create_new_settings_file(textfile_path : String): + import_data = ResourceTablesImport.new() + import_data.initialize(textfile_path) + + for format_x in formats_import: + var new_importer = format_x.new() + if new_importer.can_edit_path(textfile_path): + entries = new_importer.import_as_arrays(import_data) + import_data.prop_names = new_importer.get_properties(entries, import_data) + break + + classname_field.text = import_data.edited_path.get_file().get_basename()\ + .capitalize().replace(" ", "") + import_data.script_classname = classname_field.text + if script_path_field.text: + var existing_resource : Resource = load(script_path_field.text).new() + import_data.prop_types = ResourceTablesImport.get_resource_property_types(existing_resource, import_data.prop_names) + + else: + import_data.load_property_names_from_textfile(textfile_path, entries) + + filename_options.clear() + for i in import_data.prop_names.size(): + filename_options.add_item(import_data.prop_names[i], i) + + +func _create_prop_editors(): + for x in prop_list.get_children(): + if !x is GridContainer: x.free() + + await get_tree().process_frame + for i in import_data.prop_names.size(): + var new_node := prop_list_item_scene.instantiate() + prop_list.add_child(new_node) + var prop_type = import_data.prop_types[i] + new_node.display(import_data.prop_names[i], prop_type if !(prop_type is PackedStringArray) else ResourceTablesImport.PropType.ENUM) + new_node.connect_all_signals(self, i) + + +func _generate_class(save_script = true): + save_script = true # Built-ins didn't work in 3.x, won't change because dont wanna test rn + import_data.new_script = import_data.generate_script(entries, save_script) + if save_script: + import_data.new_script.resource_path = import_data.edited_path.get_basename() + ".gd" + ResourceSaver.save(import_data.new_script) + # Because when instanced, objects have a copy of the script + import_data.new_script = load(import_data.edited_path.get_basename() + ".gd") + + +func _on_import_to_tres_pressed(): + if script_path_field.text != "": + import_data.load_external_script(load(script_path_field.text)) + + if import_data.new_script == null: + _generate_class() + + DirAccess.open("res://").make_dir_recursive(import_data.edited_path.get_basename()) + + import_data.prop_used_as_filename = import_data.prop_names[filename_options.selected] + var new_res : Resource + for i in entries.size(): + if import_data.remove_first_row and i == 0: + continue + + new_res = import_data.strings_to_resource(entries[i], editor_view.current_path) + ResourceSaver.save(new_res) + + await get_tree().process_frame + await get_tree().process_frame + editor_view.refresh() + close() + + +func _on_import_edit_pressed(): + if import_data.new_script == null: + _generate_class(false) + + import_data.prop_used_as_filename = "" + import_data.save() + await get_tree().process_frame + editor_view.display_folder(import_data.resource_path) + editor_view.node_columns.hidden_columns[editor_view.current_path] = { + "resource_path" : true, + "resource_local_to_scene" : true, + } + editor_view.save_data() + await get_tree().process_frame + editor_view.refresh() + close() + + +func _on_export_csv_pressed(): + var exported_cols : Array = editor_view.columns.duplicate() + exported_cols.erase(&"resource_local_to_scene") + for x in editor_view.node_columns.hidden_columns[editor_view.current_path].keys(): + exported_cols.erase(x) + + ResourceTablesExportFormatCsv.export_to_file(editor_view.rows, exported_cols, import_data.edited_path, import_data) + await get_tree().process_frame + editor_view.refresh() + close() + +# Input controls +func _on_classname_field_text_changed(new_text : String): + import_data.script_classname = new_text.replace(" ", "") + + +func _on_remove_first_row_toggled(button_pressed : bool): + import_data.remove_first_row = button_pressed +# $"Export/Box2/Button".button_pressed = true + $"Export/Box3/CheckBox".button_pressed = button_pressed + + +func _on_list_item_type_selected(type : int, index : int): + import_data.prop_types[index] = type + + +func _on_list_item_name_changed(name : String, index : int): + import_data.prop_names[index] = name.replace(" ", "") + + +func _on_export_delimiter_pressed(del : String): + import_data.delimeter = del + import_data.delimeter.substr(1) + + +func _on_export_space_toggled(button_pressed : bool): + import_data.delimeter = ( + import_data.delimeter[0] + if !button_pressed else + import_data.delimeter + " " + ) + + +func _on_enum_format_changed(case, delimiter, bool_yes, bool_no): + import_data.enum_format = [case, delimiter, bool_yes, bool_no] + + +func close(): + get_parent().hide() + + +# Handles reloading the import hint editor if a Resource script is chosen +func _on_file_dialog_file_selected(path: String) -> void: + script_path_field.text = path + _on_file_selected(import_data.edited_path) diff --git a/addons/resources_spreadsheet_view/import_export/import_export_dialog.gd.uid b/addons/resources_spreadsheet_view/import_export/import_export_dialog.gd.uid new file mode 100644 index 0000000..e02a1da --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/import_export_dialog.gd.uid @@ -0,0 +1 @@ +uid://qcn5qlrm17ly diff --git a/addons/resources_spreadsheet_view/import_export/import_export_dialog.tscn b/addons/resources_spreadsheet_view/import_export/import_export_dialog.tscn new file mode 100644 index 0000000..d067c84 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/import_export_dialog.tscn @@ -0,0 +1,240 @@ +[gd_scene load_steps=8 format=3 uid="uid://b413igx28kkvb"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/import_export/import_export_dialog.gd" id="1"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/import_export/formats_export/export_csv.gd" id="2_33c6s"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/import_export/formats_import/import_csv.gd" id="2_fxayt"] +[ext_resource type="PackedScene" uid="uid://b8llymigbprh6" path="res://addons/resources_spreadsheet_view/import_export/property_list_item.tscn" id="2_xfhmf"] +[ext_resource type="PackedScene" uid="uid://ckhf3bqy2rqjr" path="res://addons/resources_spreadsheet_view/import_export/import_export_enum_format.tscn" id="4"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="5_k5rhi"] + +[sub_resource type="ButtonGroup" id="ButtonGroup_080hd"] + +[node name="TabContainer" type="TabContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +current_tab = 1 +script = ExtResource("1") +prop_list_item_scene = ExtResource("2_xfhmf") +formats_export = Array[Script]([ExtResource("2_33c6s")]) +formats_import = Array[Script]([ExtResource("2_fxayt")]) + +[node name="Import" type="VBoxContainer" parent="."] +visible = false +layout_mode = 2 +mouse_filter = 2 +metadata/_tab_index = 0 + +[node name="Margins" type="MarginContainer" parent="Import"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="Scroll" type="ScrollContainer" parent="Import/Margins"] +layout_mode = 2 +horizontal_scroll_mode = 0 + +[node name="Box" type="VBoxContainer" parent="Import/Margins/Scroll"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Grid" type="GridContainer" parent="Import/Margins/Scroll/Box"] +layout_mode = 2 +columns = 2 + +[node name="Label" type="Label" parent="Import/Margins/Scroll/Box/Grid"] +layout_mode = 2 +text = "Column Used as Filename:" + +[node name="UseAsFilename" type="OptionButton" parent="Import/Margins/Scroll/Box/Grid"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label4" type="Label" parent="Import/Margins/Scroll/Box/Grid"] +layout_mode = 2 +text = "Use Script:" + +[node name="HBoxContainer" type="HBoxContainer" parent="Import/Margins/Scroll/Box/Grid"] +layout_mode = 2 + +[node name="LineEdit" type="LineEdit" parent="Import/Margins/Scroll/Box/Grid/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "(create new GDScript)" +editable = false + +[node name="Button2" type="Button" parent="Import/Margins/Scroll/Box/Grid/HBoxContainer"] +layout_mode = 2 +script = ExtResource("5_k5rhi") +icon_name = "Clear" + +[node name="Button" type="Button" parent="Import/Margins/Scroll/Box/Grid/HBoxContainer"] +layout_mode = 2 +script = ExtResource("5_k5rhi") +icon_name = "Folder" + +[node name="FileDialog" type="FileDialog" parent="Import/Margins/Scroll/Box/Grid/HBoxContainer"] +title = "Choose Script..." +initial_position = 4 +size = Vector2i(800, 500) +ok_button_text = "Open" +mode_overrides_title = false +file_mode = 0 +filters = PackedStringArray("*.gd", "*.cs") + +[node name="Control" type="Control" parent="Import/Margins/Scroll/Box/Grid"] +layout_mode = 2 + +[node name="Label5" type="Label" parent="Import/Margins/Scroll/Box/Grid"] +self_modulate = Color(1, 0.84375, 0, 1) +layout_mode = 2 +text = "WARNING: Importing with a pre-existing Script will not import datatypes not selectible below." +horizontal_alignment = 1 +autowrap_mode = 3 + +[node name="Label2" type="Label" parent="Import/Margins/Scroll/Box/Grid"] +visible = false +layout_mode = 2 +text = "Class Name" + +[node name="Classname" type="LineEdit" parent="Import/Margins/Scroll/Box/Grid"] +visible = false +layout_mode = 2 +caret_blink = true +caret_blink_interval = 0.5 + +[node name="Label3" type="Label" parent="Import/Margins/Scroll/Box/Grid"] +layout_mode = 2 +text = "Flags:" + +[node name="Flags" type="VBoxContainer" parent="Import/Margins/Scroll/Box/Grid"] +layout_mode = 2 + +[node name="RemoveFirstRow" type="CheckBox" parent="Import/Margins/Scroll/Box/Grid/Flags"] +layout_mode = 2 +text = "First row contains property names" + +[node name="HSeparator" type="HSeparator" parent="Import/Margins/Scroll/Box"] +layout_mode = 2 + +[node name="StyleSettingsI" parent="Import/Margins/Scroll/Box" instance=ExtResource("4")] +layout_mode = 2 + +[node name="Box" type="HBoxContainer" parent="Import"] +layout_mode = 2 +mouse_filter = 2 +alignment = 1 + +[node name="Ok2" type="Button" parent="Import/Box"] +layout_mode = 2 +text = "Confirm and edit" + +[node name="Ok" type="Button" parent="Import/Box"] +layout_mode = 2 +text = "Convert to Resources and edit" + +[node name="Cancel" type="Button" parent="Import/Box"] +layout_mode = 2 +text = "Cancel" + +[node name="Control" type="Control" parent="Import"] +layout_mode = 2 +mouse_filter = 2 + +[node name="Export" type="VBoxContainer" parent="."] +layout_mode = 2 +metadata/_tab_index = 1 + +[node name="Info" type="Label" parent="Export"] +layout_mode = 2 +size_flags_vertical = 0 +text = "The currently edited folder will be exported into the selected file. + +Rows hidden by the filter will NOT be exported, and order follows the current sorting key. Rows on non-selected pages will not be removed. + +Hidden columns will NOT be exported." +autowrap_mode = 2 + +[node name="HSeparator" type="HSeparator" parent="Export"] +layout_mode = 2 + +[node name="Box" type="HBoxContainer" parent="Export"] +layout_mode = 2 +alignment = 1 + +[node name="Label2" type="Label" parent="Export/Box"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Delimiter:" + +[node name="Button" type="Button" parent="Export/Box"] +layout_mode = 2 +toggle_mode = true +button_pressed = true +button_group = SubResource("ButtonGroup_080hd") +text = "Comma (,)" + +[node name="Button2" type="Button" parent="Export/Box"] +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_080hd") +text = "Semicolon (;)" + +[node name="Button3" type="Button" parent="Export/Box"] +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_080hd") +text = "Tab" + +[node name="CheckBox" type="CheckBox" parent="Export/Box"] +layout_mode = 2 +text = "With space after" + +[node name="Box3" type="HBoxContainer" parent="Export"] +layout_mode = 2 + +[node name="CheckBox" type="CheckBox" parent="Export/Box3"] +layout_mode = 2 +text = "First row contains property names (CSV)" + +[node name="StyleSettingsE" parent="Export" instance=ExtResource("4")] +layout_mode = 2 + +[node name="Control" type="Control" parent="Export"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="Box2" type="HBoxContainer" parent="Export"] +layout_mode = 2 +alignment = 1 + +[node name="Button" type="Button" parent="Export/Box2"] +layout_mode = 2 +text = "Export to CSV" + +[node name="Cancel" type="Button" parent="Export/Box2"] +layout_mode = 2 +text = "Cancel" + +[node name="Control2" type="Control" parent="Export"] +layout_mode = 2 + +[connection signal="pressed" from="Import/Margins/Scroll/Box/Grid/HBoxContainer/Button2" to="Import/Margins/Scroll/Box/Grid/HBoxContainer/LineEdit" method="set_text" binds= [""]] +[connection signal="pressed" from="Import/Margins/Scroll/Box/Grid/HBoxContainer/Button" to="Import/Margins/Scroll/Box/Grid/HBoxContainer/FileDialog" method="popup_centered"] +[connection signal="file_selected" from="Import/Margins/Scroll/Box/Grid/HBoxContainer/FileDialog" to="Import/Margins/Scroll/Box/Grid/HBoxContainer/LineEdit" method="set_text"] +[connection signal="text_changed" from="Import/Margins/Scroll/Box/Grid/Classname" to="." method="_on_classname_field_text_changed"] +[connection signal="toggled" from="Import/Margins/Scroll/Box/Grid/Flags/RemoveFirstRow" to="." method="_on_remove_first_row_toggled"] +[connection signal="format_changed" from="Import/Margins/Scroll/Box/StyleSettingsI" to="." method="_on_enum_format_changed"] +[connection signal="format_changed" from="Import/Margins/Scroll/Box/StyleSettingsI" to="Export/StyleSettingsE" method="_on_format_changed"] +[connection signal="pressed" from="Import/Box/Ok2" to="." method="_on_import_edit_pressed"] +[connection signal="pressed" from="Import/Box/Ok" to="." method="_on_import_to_tres_pressed"] +[connection signal="pressed" from="Import/Box/Cancel" to="." method="close"] +[connection signal="pressed" from="Export/Box/Button" to="." method="_on_export_delimiter_pressed" binds= [","]] +[connection signal="pressed" from="Export/Box/Button2" to="." method="_on_export_delimiter_pressed" binds= [";"]] +[connection signal="pressed" from="Export/Box/Button3" to="." method="_on_export_delimiter_pressed" binds= [" "]] +[connection signal="toggled" from="Export/Box/CheckBox" to="." method="_on_export_space_toggled"] +[connection signal="toggled" from="Export/Box3/CheckBox" to="." method="_on_remove_first_row_toggled"] +[connection signal="format_changed" from="Export/StyleSettingsE" to="." method="_on_enum_format_changed"] +[connection signal="pressed" from="Export/Box2/Button" to="." method="_on_export_csv_pressed"] +[connection signal="pressed" from="Export/Box2/Cancel" to="." method="close"] diff --git a/addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd b/addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd new file mode 100644 index 0000000..4c5e404 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd @@ -0,0 +1,30 @@ +@tool +extends GridContainer + +signal format_changed(case : int, delimiter : String, bool_yes : String, bool_no: String) + + +func set_format_array(format : Array): + _on_format_changed(format[0], format[1], format[2], format[3]) + format_changed.emit(format[0], format[1], format[2], format[3]) + + +func set_format(case : int, delimiter : String, bool_yes : String, bool_no: String): + _on_format_changed(case, delimiter, bool_yes, bool_no) + format_changed.emit(case, delimiter, bool_yes, bool_no) + + +func _send_signal(arg1 = null): + format_changed.emit( + $"HBoxContainer/Case".selected, + [" ", "_", "-"][$"HBoxContainer/Separator".selected], + $"HBoxContainer2/True".text, + $"HBoxContainer2/False".text + ) + + +func _on_format_changed(case : int, delimiter : String, bool_yes : String, bool_no: String): + $"HBoxContainer/Case".selected = case + $"HBoxContainer/Separator".selected = [" ", "_", "-"].find(delimiter) + $"HBoxContainer2/True".text = bool_yes + $"HBoxContainer2/False".text = bool_no diff --git a/addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd.uid b/addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd.uid new file mode 100644 index 0000000..266dad9 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd.uid @@ -0,0 +1 @@ +uid://dieepcktk5bv0 diff --git a/addons/resources_spreadsheet_view/import_export/import_export_enum_format.tscn b/addons/resources_spreadsheet_view/import_export/import_export_enum_format.tscn new file mode 100644 index 0000000..e2ae440 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/import_export_enum_format.tscn @@ -0,0 +1,68 @@ +[gd_scene load_steps=2 format=3 uid="uid://ckhf3bqy2rqjr"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/import_export/import_export_enum_format.gd" id="1"] + +[node name="EnumFormat" type="GridContainer"] +columns = 2 +script = ExtResource("1") + +[node name="Label3" type="Label" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Enum word case/separator" + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Case" type="OptionButton" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +clip_text = true +selected = 2 +item_count = 4 +popup/item_0/text = "all lower" +popup/item_1/text = "caps Except First" +popup/item_1/id = 1 +popup/item_2/text = "Caps Every Word" +popup/item_2/id = 2 +popup/item_3/text = "ALL CAPS" +popup/item_3/id = 3 + +[node name="Separator" type="OptionButton" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 0.5 +clip_text = true +selected = 0 +item_count = 3 +popup/item_0/text = "Space \" \"" +popup/item_1/text = "Underscore \"_\"" +popup/item_1/id = 1 +popup/item_2/text = "Kebab \"-\"" +popup/item_2/id = 2 + +[node name="Label4" type="Label" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Boolean True/False" + +[node name="HBoxContainer2" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="True" type="LineEdit" parent="HBoxContainer2"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Yes" + +[node name="False" type="LineEdit" parent="HBoxContainer2"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "No" + +[connection signal="mouse_entered" from="Label3" to="." method="_on_Label3_mouse_entered"] +[connection signal="item_selected" from="HBoxContainer/Case" to="." method="_send_signal"] +[connection signal="item_selected" from="HBoxContainer/Separator" to="." method="_send_signal"] +[connection signal="text_changed" from="HBoxContainer2/True" to="." method="_send_signal"] +[connection signal="text_changed" from="HBoxContainer2/False" to="." method="_send_signal"] diff --git a/addons/resources_spreadsheet_view/import_export/property_list_item.gd b/addons/resources_spreadsheet_view/import_export/property_list_item.gd new file mode 100644 index 0000000..ecae660 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/property_list_item.gd @@ -0,0 +1,12 @@ +@tool +extends HBoxContainer + + +func display(name : String, type : int): + $"LineEdit".text = name + $"OptionButton".selected = type + + +func connect_all_signals(to : Object, index : int, prefix : String = "_on_list_item_"): + $"LineEdit".text_changed.connect(Callable(to, prefix + "name_changed").bind(index)) + $"OptionButton".item_selected.connect(Callable(to, prefix + "type_selected").bind(index)) diff --git a/addons/resources_spreadsheet_view/import_export/property_list_item.gd.uid b/addons/resources_spreadsheet_view/import_export/property_list_item.gd.uid new file mode 100644 index 0000000..6f9a17b --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/property_list_item.gd.uid @@ -0,0 +1 @@ +uid://hbs7m0vdhi8 diff --git a/addons/resources_spreadsheet_view/import_export/property_list_item.tscn b/addons/resources_spreadsheet_view/import_export/property_list_item.tscn new file mode 100644 index 0000000..a0732f7 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/property_list_item.tscn @@ -0,0 +1,36 @@ +[gd_scene load_steps=2 format=3 uid="uid://b8llymigbprh6"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/import_export/property_list_item.gd" id="1"] + +[node name="Entry" type="HBoxContainer"] +script = ExtResource("1") + +[node name="LineEdit" type="LineEdit" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 0.5 +text = "1" + +[node name="OptionButton" type="OptionButton" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 5 +size_flags_stretch_ratio = 0.25 +fit_to_longest_item = false +item_count = 8 +popup/item_0/text = "Bool" +popup/item_0/id = 1 +popup/item_1/text = "Integer Number" +popup/item_1/id = 2 +popup/item_2/text = "Floating Point Number" +popup/item_2/id = 3 +popup/item_3/text = "String/Other" +popup/item_3/id = 4 +popup/item_4/text = "Color" +popup/item_4/id = 14 +popup/item_5/text = "Resource Path" +popup/item_5/id = 17 +popup/item_6/text = "Enumeration" +popup/item_6/id = 101 +popup/item_7/text = "Array" +popup/item_7/id = 102 diff --git a/addons/resources_spreadsheet_view/import_export/spreadsheet_import.gd b/addons/resources_spreadsheet_view/import_export/spreadsheet_import.gd new file mode 100644 index 0000000..e0a6e38 --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/spreadsheet_import.gd @@ -0,0 +1,430 @@ +@tool +class_name ResourceTablesImport +extends Resource + +enum PropType { + BOOL, + INT, + FLOAT, + STRING, + COLOR, + OBJECT, + ENUM, + COLLECTION, + MAX, +} + +enum NameCasing { + ALL_LOWER, + CAPS_WORD_EXCEPT_FIRST, + CAPS_WORD, + ALL_CAPS, +} + +const SUFFIX := "_table_import.tres" +const TYPE_MAP := { + TYPE_STRING : PropType.STRING, + TYPE_FLOAT : PropType.FLOAT, + TYPE_BOOL : PropType.BOOL, + TYPE_INT : PropType.INT, + TYPE_OBJECT : PropType.OBJECT, + TYPE_COLOR : PropType.COLOR, + TYPE_ARRAY : PropType.COLLECTION, + TYPE_DICTIONARY : PropType.COLLECTION, +} + +@export var prop_types : Array +@export var prop_names : Array + +@export var edited_path := "res://" +@export var prop_used_as_filename := "" +@export var script_classname := "" +@export var remove_first_row := true + +@export var new_script : Script +@export var view_script : Script = ResourceTablesEditFormatCsv +@export var delimeter := ";" +@export var enum_format : Array = [NameCasing.CAPS_WORD, " ", "Yes", "No"] + +@export var uniques : Dictionary + + +func initialize(path): + edited_path = path + prop_types = [] + prop_names = [] + + +func save(): + resource_path = edited_path.get_basename() + SUFFIX + ResourceSaver.save.call_deferred(self) + + +func string_to_property(string : String, col_index : int): + match prop_types[col_index]: + PropType.STRING: + return string + + PropType.BOOL: + string = string.to_lower() + if string == enum_format[2].to_lower(): return true + if string == enum_format[3].to_lower(): return false + return !string in ["no", "disabled", "-", "false", "absent", "wrong", "off", "0", ""] + + PropType.FLOAT: + return string.to_float() + + PropType.INT: + return string.to_int() + + PropType.COLOR: + return Color(string) + + PropType.OBJECT: + return null if string == "" else load(string) + + PropType.ENUM: + if string == "": + return int(uniques[col_index]["N_A"]) + + else: + return int(uniques[col_index][string.capitalize().replace(" ", "_").to_upper()]) + # if string.is_valid_int(): + # return int(uniques[col_index][string.capitalize().replace(" ", "_").to_upper()]) + # else: + # # If the enum is a string, we actually just want the key not the value + # var enum_keys : Dictionary = uniques[col_index] + # return int(enum_keys.find_key(string)) + + PropType.COLLECTION: + var result = str_to_var(string) + if result is Array: + for i in result.size(): + if result[i] is String && result[i].begins_with("res://"): + result[i] = load(result[i]) + + if result is Dictionary: + for k in result: + if result[k] is String && result[k].begins_with("res://"): + result[k] = load(result[k]) + + if result == null: + result = [] + + return result + + +func property_to_string(value, col_index : int) -> String: + if value == null: return "" + if prop_types[col_index] is PackedStringArray: + return prop_types[col_index][value].capitalize() + + match prop_types[col_index]: + PropType.STRING: + return str(value) + + PropType.BOOL: + return enum_format[2] if value else enum_format[3] + + PropType.FLOAT, PropType.INT: + return str(value) + + PropType.COLOR: + return value.to_html() + + PropType.OBJECT: + return value.resource_path + + PropType.COLLECTION: + value = value.duplicate() + if value is Array: + for i in value.size(): + if value[i] is Resource: + value[i] = value[i].resource_path + + if value is Dictionary: + for k in value: + if value[k] is Resource: + value[k] = value[k].resource_path + + return str(value) + + PropType.ENUM: + var dict = uniques[col_index] + for k in dict: + if dict[k] == value: + return change_name_to_format(k, enum_format[0], enum_format[1]) + + return str(value) + + +func create_property_line_for_prop(col_index : int) -> String: + var result : String = "@export var " + prop_names[col_index] + " :" + match prop_types[col_index]: + PropType.STRING: + return result + "= \"\"\r\n" + + PropType.BOOL: + return result + "= false\r\n" + + PropType.FLOAT: + return result + "= 0.0\r\n" + + PropType.INT: + return result + "= 0\r\n" + + PropType.COLOR: + return result + "= Color.WHITE\r\n" + + PropType.OBJECT: + return result + " Resource\r\n" + + PropType.COLLECTION: + return result + "= []\r\n" + + PropType.ENUM: + return result + " %s\r\n" % _escape_forbidden_enum_names(prop_names[col_index].capitalize().replace(" ", "")) + # return result.replace( + # "@export var", + # "@export_enum(" + _escape_forbidden_enum_names( + # prop_names[col_index].capitalize()\ + # .replace(" ", "") + # ) + ") var" + # ) + "= 0\r\n" + + return "" + + +func _escape_forbidden_enum_names(string : String) -> String: + if ClassDB.class_exists(string): + return string + "_" + + # Not in ClassDB, but are engine types and can be property names + if string in [ + "Color", "String", "Plane", "Projection", + "Basis", "Transform", "Variant", + ]: + return string + "_" + + return string + + +func create_enum_for_prop(col_index) -> String: + var result := ( + "enum " + + _escape_forbidden_enum_names( + prop_names[col_index].capitalize().replace(" ", "") + ) + " {\r\n" + ) + for k in uniques[col_index]: + result += ( + "\t" + + k # Enum Entry + + " = " + + str(uniques[col_index][k]) # Value + + ",\r\n" + ) + result += "\tMAX,\r\n}\r\n\r\n" + + return result + + +func generate_script(entries, has_classname = true) -> GDScript: + var source := "" +# if has_classname and script_classname != "": +# source = "class_name " + script_classname + " \r\nextends Resource\r\n\r\n" +# +# else: + source = "extends Resource\r\n\r\n" + + # Enums + uniques = get_uniques(entries) + for i in prop_types.size(): + if prop_types[i] == PropType.ENUM: + source += create_enum_for_prop(i) + + # Properties + for i in prop_names.size(): + if (prop_names[i] != "resource_path") and (prop_names[i] != "resource_name"): + source += create_property_line_for_prop(i) + + var created_script : GDScript = GDScript.new() + created_script.source_code = source + created_script.reload() + return created_script + + +func load_property_names_from_textfile(path : String, loaded_entries : Array): + prop_types.resize(prop_names.size()) + prop_types.fill(4) + for i in prop_names.size(): + prop_names[i] = loaded_entries[0][i]\ + .replace("\"", "")\ + .replace(" ", "_")\ + .replace("-", "_")\ + .replace(".", "_")\ + .replace(",", "_")\ + .replace("\t", "_")\ + .replace("/", "_")\ + .replace("\\", "_")\ + .to_lower() + + var value = loaded_entries[1][i] + var value_cast = str_to_var(value) + # Don't guess Ints automatically - further rows might have floats + if value_cast is Array or value_cast is Dictionary: + prop_types[i] = ResourceTablesImport.PropType.COLLECTION + elif value.is_valid_float(): + prop_types[i] = ResourceTablesImport.PropType.FLOAT + elif value.begins_with("res://") && prop_names[i] != "resource_path": + prop_types[i] = ResourceTablesImport.PropType.OBJECT + elif value.length() == 6 or value.length() == 8 or (value.length() > 0 and value[0] == "#"): + prop_types[i] = ResourceTablesImport.PropType.COLOR + else: + prop_types[i] = ResourceTablesImport.PropType.STRING + + +func load_external_script(script_res : Script): + new_script = script_res + var result := {} + for x in script_res.get_script_property_list(): + + if x.hint != PROPERTY_HINT_ENUM or x.type != TYPE_INT: + continue + + var cur_value := "" + var result_for_prop := {} + result[prop_names.find(x.name)] = result_for_prop + var hint_arr : Array = x.hint_string.split(",") + for current_hint in hint_arr.size(): + var colon_found : int = hint_arr[current_hint].rfind(":") + cur_value = hint_arr[current_hint] + if cur_value == "": + cur_value = "N_A" + + if colon_found != -1: + var value_split := cur_value.split(":") + result_for_prop[value_split[1].to_upper()] = value_split[0] + + else: + result_for_prop[cur_value.to_upper()] = result_for_prop.size() + + uniques = result + + +func strings_to_resource(strings : Array, destination_path : String) -> Resource: + if destination_path == "": + destination_path = edited_path.get_base_dir().path_join("import/") + DirAccess.make_dir_recursive_absolute(destination_path) + + # If a full path is provided this catches that case + var new_path : String = strings[prop_names.find(prop_used_as_filename)] + + if !FileAccess.file_exists(new_path): + new_path = destination_path.path_join(new_path).trim_suffix(".tres") + ".tres" + + if !FileAccess.file_exists(new_path): + new_path = (strings[prop_names.find(prop_used_as_filename)] + .trim_prefix(destination_path) + .trim_suffix(".tres") + ".tres" + ) + if !new_path.begins_with("res://"): + new_path = destination_path.path_join(new_path) + + DirAccess.make_dir_recursive_absolute(new_path.get_base_dir()) + + var new_res : Resource + if FileAccess.file_exists(new_path): + new_res = load(new_path) + + else: + new_res = new_script.new() + new_res.resource_path = new_path + + for i in mini(prop_names.size(), strings.size()): + var skip_next := false + var cast_array := false + + # This is awful, but the workaround for typed casting + # https://github.com/godotengine/godot/issues/72620 + var property_value = string_to_property(strings[i], i) + if property_value is Array: + var property_value_as_typed := new_res.get(prop_names[i]) + property_value_as_typed.assign(property_value) + new_res.set(prop_names[i], property_value_as_typed) + + else: + new_res.set(prop_names[i], property_value) + + if prop_used_as_filename != "": + new_res.resource_path = new_path + + return new_res + + +func resource_to_strings(res : Resource): + var strings := [] + strings.resize(prop_names.size()) + for i in prop_names.size(): + strings[i] = property_to_string(res.get(prop_names[i]), i) + + return PackedStringArray(strings) + + +func get_uniques(entries : Array) -> Dictionary: + var result := {} + for i in prop_types.size(): + if prop_types[i] == PropType.ENUM: + var cur_value := "" + result[i] = {} + for j in entries.size(): + if j == 0 and remove_first_row: continue + + cur_value = entries[j][i].capitalize().to_upper().replace(" ", "_") + if cur_value == "": + cur_value = "N_A" + + if !result[i].has(cur_value): + result[i][cur_value] = result[i].size() + + return result + + +static func change_name_to_format(name : String, case : int, delim : String): + var string := name.capitalize().replace(" ", delim) + if case == NameCasing.ALL_LOWER: + return string.to_lower() + + if case == NameCasing.CAPS_WORD_EXCEPT_FIRST: + return string[0].to_lower() + string.substr(1) + + if case == NameCasing.CAPS_WORD: + return string + + if case == NameCasing.ALL_CAPS: + return string.to_upper() + + +static func get_resource_property_types(res : Resource, properties : Array) -> Array: + var result := [] + result.resize(properties.size()) + result.fill(PropType.STRING) + var cur_type := 0 + for x in res.get_property_list(): + var found := properties.find(x["name"]) + if found == -1: continue + if x["usage"] & PROPERTY_USAGE_EDITOR != 0: + if x["hint"] == PROPERTY_HINT_ENUM: + + var enum_values : PackedStringArray = x["hint_string"].split(",") + for i in enum_values.size(): + var index_found : int = enum_values[i].find(":") + if index_found == -1: continue + enum_values[i] = enum_values[i].left(index_found) + + result[found] = enum_values + + else: + result[found] = TYPE_MAP.get(x["type"], PropType.STRING) + + return result diff --git a/addons/resources_spreadsheet_view/import_export/spreadsheet_import.gd.uid b/addons/resources_spreadsheet_view/import_export/spreadsheet_import.gd.uid new file mode 100644 index 0000000..a3ccfab --- /dev/null +++ b/addons/resources_spreadsheet_view/import_export/spreadsheet_import.gd.uid @@ -0,0 +1 @@ +uid://s23fxh8eetq1 diff --git a/addons/resources_spreadsheet_view/main_screen/class_filter.gd b/addons/resources_spreadsheet_view/main_screen/class_filter.gd new file mode 100644 index 0000000..f952c77 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/class_filter.gd @@ -0,0 +1,146 @@ +@tool +extends Control + +@onready var editor_view := $"../../../../.." +@onready var node_options := $"Class" +@onready var node_subclasses_check := $"Subclasses" + +var found_builtins : Array[String] = [] +var found_scripts : Array[Script] = [] +var selected_builtin := &"" +var selected_script : Script +var selected_is_valid := false +var include_subclasses := true + + +func _ready(): + node_options.item_selected.connect(_on_item_selected) + node_subclasses_check.toggled.connect(_on_subclasses_toggled) + + +func fill(resources : Array): + node_options.clear() + found_scripts.clear() + found_builtins.clear() + var class_set := {} + for x in resources: + class_set[x.get_script()] = true + class_set[StringName(x.get_class())] = true + var current_s : Script = x.get_script() + while current_s != null: + current_s = current_s.get_base_script() + if class_set.has(current_s): + break + + class_set[current_s] = true + + var current_c : StringName = x.get_class() + while true: + if current_c == &"Resource": + break + + current_c = ClassDB.get_parent_class(current_c) + if class_set.has(current_c): + break + + class_set[current_c] = true + + class_set.erase(null) + class_set.erase("Resource") + + for k in class_set: + if k is StringName: + found_builtins.append(k) + + if k is Script: + found_scripts.append(k) + + # Add builtins, then script classes, in order. + node_options.add_item("") + for x in found_builtins: + node_options.add_item(x) + if has_theme_icon(x, &"EditorIcons"): + node_options.set_item_icon(-1, get_theme_icon(x, &"EditorIcons")) + + else: + node_options.set_item_icon(-1, get_theme_icon(&"Object", &"EditorIcons")) + + for x in found_scripts: + node_options.add_item(x.resource_path.get_file().get_basename().to_pascal_case()) + node_options.set_item_icon(-1, get_theme_icon(&"Script", &"EditorIcons")) + + node_options.add_item("") + + # Filter is disabled if the already selected class is not in the set. + if not class_set.has(selected_script) and not class_set.has(selected_builtin): + selected_is_valid = false + + # When the list is cleared, text and icon are cleared too. Setting to -1 explicitly allows changing icon and label + node_options.selected = -1 + if not selected_is_valid: + node_options.set_item_icon(-1, null) + + elif selected_builtin == &"" or selected_builtin == &"Resource": + node_options.set_item_icon(-1, get_theme_icon("Script", "EditorIcons")) + + else: + node_options.set_item_icon(-1, get_theme_icon(selected_builtin, "EditorIcons")) + + show() + + +func clear(): + selected_is_valid = false + + +func filter(resource : Resource) -> bool: + if not selected_is_valid: + return true + + if resource.get_class() != selected_builtin: + if include_subclasses and selected_script == null: + var cur_class := StringName(resource.get_class()) + while cur_class != &"Object": + cur_class = ClassDB.get_parent_class(cur_class) + if cur_class == selected_builtin: + return true + + return false + + if selected_script != null and resource.get_script() != selected_script: + if include_subclasses: + var cur_class : Script = resource.get_script() + while cur_class != null: + cur_class = cur_class.get_base_script() + if cur_class == selected_script: + return true + + return false + + + return true + + +func _on_item_selected(index : int): + if index == 0: + selected_builtin = &"" + selected_script = null + selected_is_valid = false + + elif index <= found_builtins.size(): + selected_builtin = found_builtins[index - 1] + selected_script = null + selected_is_valid = true + + elif index <= found_builtins.size() + found_scripts.size(): + selected_script = found_scripts[index - found_builtins.size() - 1] + selected_builtin = selected_script.get_instance_base_type() + selected_is_valid = true + + node_options.tooltip_text = "Selected: %s" % node_options.get_item_text(index) + editor_view.refresh() + + +func _on_subclasses_toggled(state : bool): + include_subclasses = state + editor_view.refresh() diff --git a/addons/resources_spreadsheet_view/main_screen/class_filter.gd.uid b/addons/resources_spreadsheet_view/main_screen/class_filter.gd.uid new file mode 100644 index 0000000..061593b --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/class_filter.gd.uid @@ -0,0 +1 @@ +uid://bgb0pele26jxr diff --git a/addons/resources_spreadsheet_view/main_screen/column_header_manager.gd b/addons/resources_spreadsheet_view/main_screen/column_header_manager.gd new file mode 100644 index 0000000..02e1473 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/column_header_manager.gd @@ -0,0 +1,189 @@ +@tool +extends Control + +const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd") + +@export var table_header_scene : PackedScene + +@onready var editor_view : Control = $"../../../.." +@onready var hide_columns_button : MenuButton = $"../../MenuStrip/VisibleCols" +@onready var grid : GridContainer = $"../../../MarginContainer/FooterContentSplit/Panel/Scroll/MarginContainer/TableGrid" + + +var hidden_columns := {}: + get: + var result := {} + for k_path in column_properties: + var result_one_path := {} + result[k_path] = result_one_path + for k_column in column_properties[k_path]: + for k_property in column_properties[k_path][k_column]: + if k_property == &"visibility" && [k_property]: + result[k_column] = true + + return result +var column_properties := {} +var columns := []: + set(v): + columns = v + for x in get_children(): + remove_child(x) + x.queue_free() + + var new_node : Control + for x in v: + new_node = table_header_scene.instantiate() + new_node.manager = self + add_child(new_node) + new_node.set_label(x) + new_node.get_node("Button").pressed.connect(editor_view._set_sorting.bind(x)) + + +func _ready(): + hide_columns_button\ + .get_popup()\ + .id_pressed\ + .connect(_on_visible_cols_id_pressed) + $"../../../MarginContainer/FooterContentSplit/Panel/Scroll"\ + .get_h_scroll_bar()\ + .value_changed\ + .connect(_on_h_scroll_changed) + + +func update(): + _update_hidden_columns() + _update_column_sizes() + + +func hide_column(column_index : int): + set_column_property(column_index, &"visibility", 0) + editor_view.save_data() + update() + + +func set_column_property(column_index : int, property_key : StringName, property_value): + var dict := column_properties + if !dict.has(editor_view.current_path): + dict[editor_view.current_path] = {} + + dict = dict[editor_view.current_path] + if !dict.has(columns[column_index]): + dict[columns[column_index]] = {} + + dict = dict[columns[column_index]] + dict[property_key] = property_value + + +func get_column_property(column_index : int, property_key : StringName, property_default = null): + var dict := column_properties + if !dict.has(editor_view.current_path): + return property_default + + dict = dict[editor_view.current_path] + if !dict.has(columns[column_index]): + return property_default + + dict = dict[columns[column_index]] + return dict.get(property_key, property_default) + + +func select_column(column_index : int): + editor_view.select_column(column_index) + + +func _update_column_sizes(): + if grid.get_child_count() == 0: + return + + await get_tree().process_frame + var column_headers := get_children() + + if grid.get_child_count() < column_headers.size(): return + if column_headers.size() != columns.size(): + editor_view.refresh() + return + + var clip_text : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "clip_headers") + var min_width := 0 + var cell : Control + + for i in column_headers.size(): + var header = column_headers[i] + cell = grid.get_child(i) + + header.get_child(0).clip_text = clip_text + header.custom_minimum_size.x = 0 + cell.custom_minimum_size.x = 0 + header.size.x = 0 + + min_width = max(header.size.x, cell.size.x) + header.custom_minimum_size.x = min_width + cell.custom_minimum_size.x = header.get_minimum_size().x + header.size.x = min_width + + grid.hide() + grid.show() + hide() + show() + await get_tree().process_frame + + # Abort if the node has been deleted since. + if !is_instance_valid(column_headers[0]): + return + + get_parent().custom_minimum_size.y = column_headers[0].size.y + for i in column_headers.size(): + column_headers[i].position.x = grid.get_child(i).position.x + column_headers[i].size.x = grid.get_child(i).size.x + + +func _update_hidden_columns(): + var current_path : String = editor_view.current_path + var rows_shown : int = editor_view.last_row - editor_view.first_row + + if !column_properties.has(current_path): + column_properties[current_path] = { + "resource_local_to_scene" : { &"visibility" : 0 }, + "resource_name" : { &"visibility" : 0 }, + "metadata/_custom_type_script" : { &"visibility" : 0 }, + } + editor_view.save_data() + + var visible_column_count := 0 + for i in columns.size(): + var column_visible : bool = get_column_property(i, &"visibility", 1) != 0 + get_child(i).visible = column_visible + for j in rows_shown: + grid.get_child(j * columns.size() + i).visible = column_visible + + if column_visible: + visible_column_count += 1 + + grid.columns = maxi(visible_column_count, 1) + + +func _on_h_scroll_changed(value): + position.x = -value + + +func _on_visible_cols_about_to_popup(): + var popup := hide_columns_button.get_popup() + popup.clear() + popup.hide_on_checkable_item_selection = false + for i in columns.size(): + popup.add_check_item(columns[i].capitalize(), i) + popup.set_item_checked(i, get_column_property(i, &"visibility", 1) != 0) + + +func _on_visible_cols_id_pressed(id : int): + var popup := hide_columns_button.get_popup() + if popup.is_item_checked(id): + popup.set_item_checked(id, false) + set_column_property(id, &"visibility", 0) + + else: + popup.set_item_checked(id, true) + set_column_property(id, &"visibility", 1) + + editor_view.save_data() + update() diff --git a/addons/resources_spreadsheet_view/main_screen/column_header_manager.gd.uid b/addons/resources_spreadsheet_view/main_screen/column_header_manager.gd.uid new file mode 100644 index 0000000..a6a35fc --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/column_header_manager.gd.uid @@ -0,0 +1 @@ +uid://dlt5lx44spko8 diff --git a/addons/resources_spreadsheet_view/main_screen/expression_textfield.gd b/addons/resources_spreadsheet_view/main_screen/expression_textfield.gd new file mode 100644 index 0000000..71ef67f --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/expression_textfield.gd @@ -0,0 +1,173 @@ +@tool +extends Control + +@export var editor_view_path : NodePath + +@export_enum("Filter", "Process", "Sort") var mode := 0 +@export var title := "" +@export var default_text := "": + set(v): + default_text = v + if _textfield == null: + await ready + + _textfield.text = v +@export_multiline var default_text_ml := "": + set(v): + default_text_ml = v + if _textfield_ml == null: + await ready + + _textfield_ml.text = v +@export var function_save_key := "" + +var _textfield : LineEdit +var _textfield_ml : TextEdit +var _togglable_popup : PopupPanel +var _saved_function_index_label : Label + +var _saved_functions : Array = [] +var _saved_function_selected := -1 + + +func load_saved_functions(func_dict : Dictionary): + if !func_dict.has(function_save_key): + func_dict[function_save_key] = [default_text_ml] + + _saved_functions = func_dict[function_save_key] + _on_saved_function_selected(0) + + +func _ready(): + var toggle_button := Button.new() + var popup_box := VBoxContainer.new() + var popup_buttons_box := HBoxContainer.new() + var title_label := Label.new() + var submit_button := Button.new() + var move_label := Label.new() + var move_button_l := Button.new() + var move_button_r := Button.new() + _textfield = LineEdit.new() + _togglable_popup = PopupPanel.new() + _textfield_ml = TextEdit.new() + _saved_function_index_label = Label.new() + + add_child(_textfield) + add_child(toggle_button) + _textfield.add_child(_togglable_popup) + _togglable_popup.add_child(popup_box) + popup_box.add_child(title_label) + popup_box.add_child(_textfield_ml) + popup_box.add_child(popup_buttons_box) + popup_buttons_box.add_child(submit_button) + popup_buttons_box.add_child(move_label) + popup_buttons_box.add_child(move_button_l) + popup_buttons_box.add_child(_saved_function_index_label) + popup_buttons_box.add_child(move_button_r) + + title_label.text = title + + toggle_button.icon = get_theme_icon("Collapse", "EditorIcons") + toggle_button.pressed.connect(_on_expand_pressed) + + _textfield.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _textfield.text_submitted.connect(_on_text_submitted.unbind(1)) + + _textfield_ml.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _textfield_ml.size_flags_vertical = Control.SIZE_EXPAND_FILL + + submit_button.text = "Run multiline!" + submit_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL + submit_button.pressed.connect(_on_text_submitted) + + move_label.text = "Choose saved:" + move_button_l.icon = get_theme_icon("PagePrevious", "EditorIcons") + move_button_l.pressed.connect(_on_saved_function_bumped.bind(-1)) + _on_saved_function_selected(0) + move_button_r.icon = get_theme_icon("PageNext", "EditorIcons") + move_button_r.pressed.connect(_on_saved_function_bumped.bind(+1)) + + + +func _on_expand_pressed(): + _togglable_popup.popup(Rect2i(_textfield.get_screen_position(), Vector2(size.x, 256.0))) + + +func _on_text_submitted(): + [_table_filter, _table_process][mode].call() + _saved_functions[_saved_function_selected] = _textfield_ml.text + get_node(editor_view_path).save_data.call_deferred() + + +func _get_script_source_code(first_line : String): + var new_text := "" + if !_togglable_popup.visible: + new_text = _textfield.text + if new_text == "": + new_text = default_text + + return first_line + "\treturn " + new_text + + else: + new_text = _textfield_ml.text + if new_text == "": + new_text = default_text_ml + + var text_split := new_text.split("\n") + for i in text_split.size(): + text_split[i] = "\t" + text_split[i] + + return first_line + "\n".join(text_split) + + +func _table_filter(): + var new_script := GDScript.new() + new_script.source_code = _get_script_source_code("static func can_show(res, index):\n") + new_script.reload() + + var editor_view := get_node(editor_view_path) + editor_view.search_cond = new_script.can_show + editor_view.refresh() + + +func _table_process(): + var new_script := GDScript.new() + new_script.source_code = _get_script_source_code("static func get_result(value, res, all_res, row_index):\n") + new_script.reload() + + var editor_view := get_node(editor_view_path) + var new_script_instance := new_script.new() + var values : Array = editor_view.get_edited_cells_values() + + var edited_rows : Array[int] = editor_view._selection.get_edited_rows() + var edited_resources := edited_rows.map(func(x): return editor_view.rows[x]) + for i in values.size(): + values[i] = new_script_instance.get_result(values[i], editor_view.rows[edited_rows[i]], edited_resources, i) + + editor_view.set_edited_cells_values(values) + + +func _on_saved_function_selected(new_index : int): + if new_index < 0: + new_index = 0 + + if _saved_function_selected == _saved_functions.size() - 1 and _textfield_ml.text == default_text_ml: + _saved_functions.resize(_saved_functions.size() - 1) + + elif _saved_function_selected >= 0: + _saved_functions[_saved_function_selected] = _textfield_ml.text + + _saved_function_selected = new_index + if new_index >= _saved_functions.size(): + _saved_functions.resize(new_index + 1) + for i in _saved_functions.size(): + if _saved_functions[i] == null: + _saved_functions[i] = default_text_ml + + _textfield_ml.text = _saved_functions[new_index] + _saved_function_index_label.text = "%d/%d" % [new_index + 1, _saved_functions.size()] + get_node(editor_view_path).save_data.call_deferred() + + +func _on_saved_function_bumped(increment : int): + _on_saved_function_selected(_saved_function_selected + increment) diff --git a/addons/resources_spreadsheet_view/main_screen/expression_textfield.gd.uid b/addons/resources_spreadsheet_view/main_screen/expression_textfield.gd.uid new file mode 100644 index 0000000..7f20677 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/expression_textfield.gd.uid @@ -0,0 +1 @@ +uid://dnvnja81uouel diff --git a/addons/resources_spreadsheet_view/main_screen/frozen_columns.gd b/addons/resources_spreadsheet_view/main_screen/frozen_columns.gd new file mode 100644 index 0000000..b722523 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/frozen_columns.gd @@ -0,0 +1,60 @@ +@tool +extends ColorRect + +const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd") + +@onready var editor_view : Control = $"../../../../../.." +@onready var grid_scroll : ScrollContainer = $"../../Scroll" +@onready var grid : GridContainer = $"../../Scroll/MarginContainer/TableGrid" + +var children : Array[Control] = [] +var children_copy_cells : Array[Control] = [] + + +func _ready() -> void: + grid_scroll.get_h_scroll_bar().value_changed.connect(_on_scroll_updated, CONNECT_DEFERRED) + grid_scroll.get_v_scroll_bar().value_changed.connect(_on_scroll_updated, CONNECT_DEFERRED) + + +func _on_grid_updated() -> void: + if editor_view.rows.size() == 0: + hide() + return + + visible = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "freeze_first_column") + for x in get_children(): + x.queue_free() + + children.clear() + children_copy_cells.clear() + size.x = 0.0 + + await get_tree().process_frame + + var first_visible_column := 0 + for i in grid.columns: + if grid.get_child(i).visible: + first_visible_column = i + break + + var total_column_count : int = editor_view.columns.size() + children.resize(grid.get_child_count() / total_column_count) + children_copy_cells.resize(children.size()) + for i in children.size(): + children_copy_cells[i] = grid.get_child(total_column_count * i + first_visible_column) + children[i] = children_copy_cells[i].duplicate() + children[i].mouse_filter = Control.MOUSE_FILTER_IGNORE + add_child(children[i]) + size.x = maxf(size.x, children_copy_cells[i].size.x) + + size.y = grid.size.y + color = get_theme_color(&"background", &"Editor") + color.a *= 0.9 + _on_scroll_updated(0.0) + + +func _on_scroll_updated(_new_value : float): + position = Vector2(0.0, -grid_scroll.scroll_vertical) + for i in children.size(): + children[i].size = children_copy_cells[i].size + children[i].position = children_copy_cells[i].position diff --git a/addons/resources_spreadsheet_view/main_screen/frozen_columns.gd.uid b/addons/resources_spreadsheet_view/main_screen/frozen_columns.gd.uid new file mode 100644 index 0000000..22b616d --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/frozen_columns.gd.uid @@ -0,0 +1 @@ +uid://dfccmqqf575do diff --git a/addons/resources_spreadsheet_view/main_screen/input_handler.gd b/addons/resources_spreadsheet_view/main_screen/input_handler.gd new file mode 100644 index 0000000..0778e7d --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/input_handler.gd @@ -0,0 +1,148 @@ +@tool +extends Node + +const TablesPluginEditorViewClass := preload("res://addons/resources_spreadsheet_view/editor_view.gd") +const TablesPluginSelectionManagerClass := preload("res://addons/resources_spreadsheet_view/main_screen/selection_manager.gd") +const TextEditingUtilsClass := preload("res://addons/resources_spreadsheet_view/text_editing_utils.gd") + +@onready var editor_view : TablesPluginEditorViewClass = get_parent() +@onready var selection : TablesPluginSelectionManagerClass = get_node("../SelectionManager") + + +func _on_cell_gui_input(event : InputEvent, cell_node : Control): + var cell := selection.get_cell_node_position(cell_node) + if event is InputEventMouseButton: + editor_view.grab_focus() + if event.button_index == MOUSE_BUTTON_RIGHT and event.pressed: + if !cell in selection.edited_cells: + selection.deselect_all_cells() + selection.select_cell(cell) + + selection.rightclick_cells() + + if event.button_index == MOUSE_BUTTON_LEFT and event.pressed: + if event.is_command_or_control_pressed(): + if cell in selection.edited_cells: + selection.deselect_cell(cell) + + else: + selection.select_cell(cell) + + elif Input.is_key_pressed(KEY_SHIFT): + selection.select_cells_to(cell) + + else: + selection.deselect_all_cells() + selection.select_cell(cell) + + +func _gui_input(event : InputEvent): + if event is InputEventMouseButton: + if event.button_index == MOUSE_BUTTON_RIGHT and event.is_pressed(): + selection.rightclick_cells() + + if event.button_index == MOUSE_BUTTON_LEFT: + editor_view.grab_focus() + if !event.pressed: + selection.deselect_all_cells() + + +func _input(event : InputEvent): + if !event is InputEventKey or !event.pressed: + return + + if !editor_view.has_focus() or selection.edited_cells.size() == 0: + return + + if event.keycode == KEY_CTRL or event.keycode == KEY_SHIFT or event.keycode == KEY_META: + # Modifier keys do not get processed. + return + + # Ctrl + Z (before, and instead of, committing the action!) + if event.is_command_or_control_pressed(): + if event.keycode == KEY_Z or event.keycode == KEY_Y: + return + + _key_specific_action(event) + editor_view.grab_focus() + editor_view.editor_interface.get_resource_filesystem().scan() + + +func _key_specific_action(event : InputEvent): + var column := selection.get_cell_column(selection.edited_cells[0]) + var ctrl_pressed : bool = event.is_command_or_control_pressed() + + # BETWEEN-CELL NAVIGATION + var grid_move_offset := (10 if ctrl_pressed else 1) + if event.keycode == KEY_UP: + _move_selection_on_grid(0, -grid_move_offset) + + elif event.keycode == KEY_DOWN: + _move_selection_on_grid(0, +grid_move_offset) + + elif Input.is_key_pressed(KEY_SHIFT) and event.keycode == KEY_TAB: + _move_selection_on_grid(-grid_move_offset, 0) + + elif event.keycode == KEY_TAB: + _move_selection_on_grid(+grid_move_offset, 0) + + elif ctrl_pressed and event.keycode == KEY_C: + TextEditingUtilsClass.multi_copy(selection.edited_cells_text) + get_viewport().set_input_as_handled() + + # Ctrl + V + elif ctrl_pressed and event.keycode == KEY_V and editor_view.columns[column] != "resource_path": + selection.clipboard_paste() + get_viewport().set_input_as_handled() + + # TEXT CARET MOVEMENT + var caret_move_offset := TextEditingUtilsClass.get_caret_movement_from_key(event.keycode) + if TextEditingUtilsClass.multi_move_caret(caret_move_offset, selection.edited_cells_text, selection.edit_cursor_positions, ctrl_pressed): + selection.queue_redraw() + return + + # The following actions do not work on non-editable cells. + if !selection.column_editors[column].is_text() or editor_view.columns[column] == "resource_path": + return + + # ERASING + elif event.keycode == KEY_BACKSPACE: + editor_view.set_edited_cells_values_text(TextEditingUtilsClass.multi_erase_left( + selection.edited_cells_text, selection.edit_cursor_positions, ctrl_pressed + )) + + elif event.keycode == KEY_DELETE: + editor_view.set_edited_cells_values_text(TextEditingUtilsClass.multi_erase_right( + selection.edited_cells_text, selection.edit_cursor_positions, ctrl_pressed + )) + get_viewport().set_input_as_handled() + + # And finally, text typing. + elif event.keycode == KEY_ENTER: + editor_view.set_edited_cells_values_text(TextEditingUtilsClass.multi_input( + "\n", selection.edited_cells_text, selection.edit_cursor_positions + )) + + elif event.unicode != 0 and event.unicode != 127: + editor_view.set_edited_cells_values_text(TextEditingUtilsClass.multi_input( + char(event.unicode), selection.edited_cells_text, selection.edit_cursor_positions + )) + + selection.queue_redraw() + + +func _move_selection_on_grid(move_h : int, move_v : int): + var selected_cells := selection.edited_cells.duplicate() + var num_columns := editor_view.columns.size() + var num_rows := editor_view.rows.size() + var new_child_pos := Vector2i(0, 0) + for i in selected_cells.size(): + new_child_pos = Vector2i( + clamp(selected_cells[i].x + move_h, 0, num_columns - 1), + clamp(selected_cells[i].y + move_v, 0, num_rows - 1), + ) + selected_cells[i] = new_child_pos + + editor_view.grab_focus() + selection.deselect_all_cells() + selection.select_cells(selected_cells) diff --git a/addons/resources_spreadsheet_view/main_screen/input_handler.gd.uid b/addons/resources_spreadsheet_view/main_screen/input_handler.gd.uid new file mode 100644 index 0000000..e14bf85 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/input_handler.gd.uid @@ -0,0 +1 @@ +uid://dmt7jkj77pcol diff --git a/addons/resources_spreadsheet_view/main_screen/recent_paths.gd b/addons/resources_spreadsheet_view/main_screen/recent_paths.gd new file mode 100644 index 0000000..bb9f3ec --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/recent_paths.gd @@ -0,0 +1,54 @@ +@tool +extends OptionButton + +@onready var editor_view := $"../../../../.." + +var recent_paths := [] + + +func _ready(): + item_selected.connect(_on_item_selected) + + +func load_paths(paths): + clear() + for x in paths: + add_path_to_recent(x, true) + + selected = 0 + + +func add_path_to_recent(path : String, is_loading : bool = false): + if path in recent_paths: return + + var idx_in_array := recent_paths.find(path) + if idx_in_array != -1: + remove_item(idx_in_array) + recent_paths.remove_at(idx_in_array) + + recent_paths.append(path) + add_item(path) + select(get_item_count() - 1) + + if !is_loading: + editor_view.save_data() + + +func remove_selected_path_from_recent(): + if get_item_count() == 0: + return + + var idx_in_array := selected + recent_paths.remove_at(idx_in_array) + remove_item(idx_in_array) + + if get_item_count() != 0: + select(0) + editor_view.display_folder(recent_paths[0]) + editor_view.save_data() + + +func _on_item_selected(index : int): + editor_view.current_path = recent_paths[index] + editor_view.node_folder_path.text = recent_paths[index] + editor_view.refresh() diff --git a/addons/resources_spreadsheet_view/main_screen/recent_paths.gd.uid b/addons/resources_spreadsheet_view/main_screen/recent_paths.gd.uid new file mode 100644 index 0000000..a93c963 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/recent_paths.gd.uid @@ -0,0 +1 @@ +uid://2jnewnqyyha3 diff --git a/addons/resources_spreadsheet_view/main_screen/selection_actions.gd b/addons/resources_spreadsheet_view/main_screen/selection_actions.gd new file mode 100644 index 0000000..4e4682e --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/selection_actions.gd @@ -0,0 +1,191 @@ +@tool +extends MarginContainer + +enum { + EDITBOX_DUPLICATE = 1, + EDITBOX_RENAME, + EDITBOX_DELETE, +} + +const TextEditingUtilsClass := preload("res://addons/resources_spreadsheet_view/text_editing_utils.gd") +const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd") + +@onready var editor_view := $"../.." +@onready var selection := $"../../SelectionManager" + +@onready var editbox_node := $"Control/ColorRect/Popup" +@onready var editbox_label : Label = editbox_node.get_node("Panel/VBoxContainer/Label") +@onready var editbox_input : LineEdit = editbox_node.get_node("Panel/VBoxContainer/LineEdit") + +var cell : Control +var editbox_action : int + + +func _ready(): + editbox_input.get_node("../..").add_theme_stylebox_override( + "panel", + get_theme_stylebox(&"Content", &"EditorStyles") + ) + editbox_input.text_submitted.connect(func(_new_text): _on_editbox_accepted()) + close() + + +func _on_grid_cells_rightclicked(cells): + open(cells) + + +func _on_grid_cells_selected(cells): + open(cells, true, true) + + +func open(cells : Array, pin_to_cell : bool = false, from_leftclick : bool = false): + if cells.size() == 0 or (from_leftclick and !ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "context_menu_on_leftclick")): + hide() + cell = null + return + + if pin_to_cell: + cell = selection.get_cell_node_from_position(cells[-1]) + set_deferred(&"global_position", Vector2( + cell.global_position.x + cell.size.x, + cell.global_position.y + )) + + else: + cell = null + set_deferred(&"global_position", get_global_mouse_position() + Vector2.ONE) + + show() + size = Vector2.ZERO + top_level = true + $"Control2/Label".text = str(cells.size()) + (" Cells" if cells.size() % 10 != 1 else " Cell") + $"GridContainer/Rename".visible = editor_view.has_row_names() + $"GridContainer/SoloOpen".visible = editor_view.column_can_solo_open(editor_view.get_selected_column()) + + +func close(): + pass + + +func _input(event : InputEvent): + if !editor_view.is_visible_in_tree(): + close() + return + + if event is InputEventMouseButton and event.is_pressed(): + close() + return + + if event is InputEventKey: + if event.is_pressed() and event.is_command_or_control_pressed(): + global_position = get_global_mouse_position() + Vector2.ONE + if cell != null: + global_position = Vector2( + cell.global_position.x + cell.size.x, + cell.global_position.y + ) + + # Dupe + if event.keycode == KEY_D: + _on_Duplicate_pressed() + return + + # Rename + if event.keycode == KEY_R: + _on_Rename_pressed() + return + + +func _on_Duplicate_pressed(): + _show_editbox(EDITBOX_DUPLICATE) + + +func _on_CbCopy_pressed(): + TextEditingUtilsClass.multi_copy(selection.edited_cells_text) + + +func _on_CbPaste_pressed(): + selection.clipboard_paste() + + +func _on_Rename_pressed(): + _show_editbox(EDITBOX_RENAME) + + +func _on_Delete_pressed(): + _show_editbox(EDITBOX_DELETE) + + +func _on_SoloOpen_pressed(): + var resources_to_open_unique := {} + for x in editor_view.get_edited_cells_values(): + if x is Array: + for y in x: + resources_to_open_unique[y] = true + + if x is Resource: + resources_to_open_unique[x] = true + + if resources_to_open_unique.size() > 0: + editor_view.display_resources(resources_to_open_unique.keys()) + + +func _show_editbox(action): + editbox_action = action + match action: + EDITBOX_DUPLICATE: + if !editor_view.has_row_names(): + _on_editbox_accepted() + return + + if selection.edited_cells.size() == 1: + editbox_label.text = "Input new row's name..." + editbox_input.text = editor_view.get_last_selected_row()\ + .resource_path.get_file().get_basename() + + else: + editbox_label.text = "Input suffix to append to names..." + editbox_input.text = "" + + EDITBOX_RENAME: + editbox_label.text = "Input new name for row..." + editbox_input.text = editor_view.get_last_selected_row()\ + .resource_path.get_file().get_basename() + + EDITBOX_DELETE: + editbox_label.text = "Really delete selected rows? (Irreversible!!!)" + editbox_input.text = editor_view.get_last_selected_row()\ + .resource_path.get_file().get_basename() + + show() + editbox_input.grab_focus() + editbox_input.caret_column = 999999999 + editbox_node.size = Vector2.ZERO + editbox_node.show() + $"Control/ColorRect".show() + $"Control/ColorRect".top_level = true + $"Control/ColorRect".size = get_viewport_rect().size * 4.0 + editbox_node.global_position = ( + global_position + + size * 0.5 + - editbox_node.get_child(0).size * 0.5 + ) + + +func _on_editbox_closed(): + editbox_node.hide() + $"Control/ColorRect".hide() + + +func _on_editbox_accepted(): + match(editbox_action): + EDITBOX_DUPLICATE: + editor_view.duplicate_selected_rows(editbox_input.text) + + EDITBOX_RENAME: + editor_view.rename_row(editor_view.get_last_selected_row(), editbox_input.text) + + EDITBOX_DELETE: + editor_view.delete_selected_rows() + + _on_editbox_closed() diff --git a/addons/resources_spreadsheet_view/main_screen/selection_actions.gd.uid b/addons/resources_spreadsheet_view/main_screen/selection_actions.gd.uid new file mode 100644 index 0000000..68c4582 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/selection_actions.gd.uid @@ -0,0 +1 @@ +uid://dnh4bwms2r20x diff --git a/addons/resources_spreadsheet_view/main_screen/selection_actions.tscn b/addons/resources_spreadsheet_view/main_screen/selection_actions.tscn new file mode 100644 index 0000000..a051f6a --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/selection_actions.tscn @@ -0,0 +1,191 @@ +[gd_scene load_steps=7 format=3 uid="uid://b51hnttsie7k5"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="1"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/selection_actions.gd" id="1_qv6ov"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_color_setter.gd" id="2_a4ihj"] + +[sub_resource type="Image" id="Image_pjk43"] +data = { +"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +"format": "LumAlpha8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id="2"] +image = SubResource("Image_pjk43") + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_r2l2b"] +content_margin_left = 4.0 +content_margin_top = 4.0 +content_margin_right = 4.0 +content_margin_bottom = 4.0 +bg_color = Color(1, 0.365, 0.365, 1) +draw_center = false +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +corner_detail = 1 + +[node name="SelectionActions" type="MarginContainer"] +offset_right = 80.0 +offset_bottom = 52.0 +size_flags_horizontal = 9 +mouse_filter = 2 +script = ExtResource("1_qv6ov") + +[node name="Control2" type="Panel" parent="."] +layout_mode = 2 +mouse_filter = 2 + +[node name="ColorRect" type="ColorRect" parent="Control2"] +show_behind_parent = true +layout_mode = 0 +mouse_filter = 2 + +[node name="ColorRect2" type="ColorRect" parent="Control2"] +modulate = Color(0, 0, 0, 1) +show_behind_parent = true +layout_mode = 1 +anchors_preset = 9 +anchor_bottom = 1.0 +offset_left = -2.0 +grow_vertical = 2 +mouse_filter = 2 +script = ExtResource("2_a4ihj") + +[node name="Label" type="Label" parent="Control2"] +layout_mode = 0 +offset_top = -26.0 +offset_right = 57.0 +text = "Actions" +vertical_alignment = 2 + +[node name="ColorRect3" type="Panel" parent="Control2/Label"] +show_behind_parent = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = -2.0 +offset_top = 2.0 +offset_right = 2.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 + +[node name="GridContainer" type="GridContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 9 +size_flags_vertical = 9 +mouse_filter = 2 +columns = 3 + +[node name="Duplicate" type="Button" parent="GridContainer"] +layout_mode = 2 +tooltip_text = "Duplicate Selected Rows (Ctrl+D)" +mouse_filter = 1 +icon = SubResource("2") +script = ExtResource("1") +icon_name = "Duplicate" + +[node name="CbCopy" type="Button" parent="GridContainer"] +layout_mode = 2 +tooltip_text = "Copy to Clipboard (Ctrl+C)" +mouse_filter = 1 +icon = SubResource("2") +script = ExtResource("1") +icon_name = "ActionCopy" + +[node name="CbPaste" type="Button" parent="GridContainer"] +layout_mode = 2 +tooltip_text = "Paste Clipboard (Ctrl+V)" +mouse_filter = 1 +icon = SubResource("2") +script = ExtResource("1") +icon_name = "ActionPaste" + +[node name="Rename" type="Button" parent="GridContainer"] +layout_mode = 2 +tooltip_text = "Rename Selected Rows (Ctrl+R)" +mouse_filter = 1 +icon = SubResource("2") +script = ExtResource("1") +icon_name = "Edit" + +[node name="Delete" type="Button" parent="GridContainer"] +layout_mode = 2 +tooltip_text = "DELETE Selected Rows" +mouse_filter = 1 +icon = SubResource("2") +script = ExtResource("1") +icon_name = "Remove" + +[node name="SoloOpen" type="Button" parent="GridContainer"] +layout_mode = 2 +tooltip_text = "Open selected cells as new table" +mouse_filter = 1 +icon = SubResource("2") +script = ExtResource("1") +icon_name = "Object" + +[node name="Control" type="Control" parent="."] +layout_mode = 2 +mouse_filter = 2 + +[node name="ColorRect" type="ColorRect" parent="Control"] +visible = false +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = -80.0 +offset_bottom = -52.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0, 0, 0, 0.498039) + +[node name="Popup" type="MarginContainer" parent="Control/ColorRect"] +layout_mode = 0 +offset_top = 100.0 +offset_right = 140.0 +offset_bottom = 196.0 + +[node name="Panel" type="PanelContainer" parent="Control/ColorRect/Popup"] +layout_mode = 2 +mouse_filter = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_r2l2b") + +[node name="VBoxContainer" type="VBoxContainer" parent="Control/ColorRect/Popup/Panel"] +layout_mode = 2 +mouse_filter = 2 + +[node name="Label" type="Label" parent="Control/ColorRect/Popup/Panel/VBoxContainer"] +layout_mode = 2 +text = "Input new name..." + +[node name="LineEdit" type="LineEdit" parent="Control/ColorRect/Popup/Panel/VBoxContainer"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="Control/ColorRect/Popup/Panel/VBoxContainer"] +layout_mode = 2 +alignment = 1 + +[node name="Button" type="Button" parent="Control/ColorRect/Popup/Panel/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "OK" + +[node name="Button2" type="Button" parent="Control/ColorRect/Popup/Panel/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Cancel" + +[connection signal="pressed" from="GridContainer/Duplicate" to="." method="_on_Duplicate_pressed"] +[connection signal="pressed" from="GridContainer/CbCopy" to="." method="_on_CbCopy_pressed"] +[connection signal="pressed" from="GridContainer/CbPaste" to="." method="_on_CbPaste_pressed"] +[connection signal="pressed" from="GridContainer/Rename" to="." method="_on_Rename_pressed"] +[connection signal="pressed" from="GridContainer/Delete" to="." method="_on_Delete_pressed"] +[connection signal="pressed" from="GridContainer/SoloOpen" to="." method="_on_SoloOpen_pressed"] +[connection signal="pressed" from="Control/ColorRect/Popup/Panel/VBoxContainer/HBoxContainer/Button" to="." method="_on_editbox_accepted"] +[connection signal="pressed" from="Control/ColorRect/Popup/Panel/VBoxContainer/HBoxContainer/Button2" to="." method="_on_editbox_closed"] diff --git a/addons/resources_spreadsheet_view/main_screen/selection_manager.gd b/addons/resources_spreadsheet_view/main_screen/selection_manager.gd new file mode 100644 index 0000000..8fa25ce --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/selection_manager.gd @@ -0,0 +1,303 @@ +@tool +extends Control + +signal cells_selected(cells_positions) +signal cells_rightclicked(cells_positions) + +const EditorViewClass := preload("res://addons/resources_spreadsheet_view/editor_view.gd") +const TextEditingUtilsClass := preload("res://addons/resources_spreadsheet_view/text_editing_utils.gd") + +@export var cell_editor_classes : Array[Script] = [] + +@onready var node_property_editors : VBoxContainer = $"../HeaderContentSplit/MarginContainer/FooterContentSplit/Footer/PropertyEditors" +@onready var scrollbar : ScrollContainer = $"../HeaderContentSplit/MarginContainer/FooterContentSplit/Panel/Scroll" + +@onready var editor_view : EditorViewClass = get_parent() + +var edited_cells : Array = [] +var edited_cells_text : Array = [] +var edit_cursor_positions : Array[int] = [] + +var all_cell_editors : Array = [] +var column_editors : Array[Object] = [] +var inspector_resource : Resource + + +func _ready(): + # Load cell editors and instantiate them + for x in cell_editor_classes: + all_cell_editors.append(x.new()) + all_cell_editors[all_cell_editors.size() - 1].hint_strings_array = editor_view.column_hint_strings + + get_parent()\ + .editor_interface\ + .get_inspector()\ + .property_edited\ + .connect(_on_inspector_property_edited) + + scrollbar.get_h_scroll_bar().value_changed.connect(queue_redraw.unbind(1), CONNECT_DEFERRED) + scrollbar.get_v_scroll_bar().value_changed.connect(queue_redraw.unbind(1), CONNECT_DEFERRED) + + if ProjectSettings.get_setting(editor_view.TablesPluginSettingsClass.PREFIX + "fold_docks", false): + for x in node_property_editors.get_children(): + x.resize_set_hidden(true) + + +func _draw(): + if edited_cells.size() == 0 or edit_cursor_positions.size() != edited_cells.size() or !column_editors[edited_cells[0].x].is_text(): + return + + var font := get_theme_font(&"font", &"Label") + var font_size := get_theme_font_size(&"font", &"Label") + var caret_color := get_theme_color(&"caret_color", &"LineEdit") + var label_padding_left := 2.0 + var newline_char := 10 + for i in edited_cells.size(): + var cell : Control = get_cell_node_from_position(edited_cells[i]) + var caret_rect := TextEditingUtilsClass.get_caret_rect(edited_cells_text[i], edit_cursor_positions[i], font, font_size, label_padding_left, 1.0) + caret_rect.position += cell.global_position - global_position + draw_rect(caret_rect, caret_color) + + +func initialize_editors(column_values, column_types, column_hints): + _set_visible_selected(false) + column_editors.clear() + for i in column_values.size(): + for x in all_cell_editors: + if x.can_edit_value(column_values[i], column_types[i], column_hints[i], i): + column_editors.append(x) + break + + +func deselect_all_cells(): + _set_visible_selected(false) + edited_cells.clear() + edited_cells_text.clear() + edit_cursor_positions.clear() + _selection_changed() + + +func deselect_cell(cell : Vector2i): + var idx := edited_cells.find(cell) + if idx == -1: return + + edited_cells.remove_at(idx) + if edited_cells_text.size() != 0: + edited_cells_text.remove_at(idx) + edit_cursor_positions.remove_at(idx) + + var cell_node := get_cell_node_from_position(cell) + if cell_node != null: + column_editors[get_cell_column(cell)].set_selected(cell_node, false) + + _selection_changed() + + +func select_cell(cell : Vector2i): + var column_index := get_cell_column(cell) + if edited_cells.size() == 0 or edited_cells[0].x == cell.x: + _add_cell_to_selection(cell) + _try_open_docks(cell) + inspector_resource = editor_view.rows[get_cell_row(cell)] + editor_view.editor_plugin.get_editor_interface().edit_resource(inspector_resource) + + _selection_changed() + + +func select_cells(cells : Array): + var last_selectible := Vector2i(-1, -1) + var started_empty := edited_cells.size() == 0 + for x in cells: + if started_empty or edited_cells[0].x != x.x: + _add_cell_to_selection(x) + if get_cell_node_from_position(x) != null: + last_selectible = x + + if last_selectible != Vector2i(-1, -1): + select_cell(last_selectible) + + +func select_cells_to(cell : Vector2i): + var column_index := get_cell_column(cell) + if edited_cells.size() == 0 or column_index != get_cell_column(edited_cells[-1]): + return + + var row_start := get_cell_row(edited_cells[-1]) + var row_end := get_cell_row(cell) + var edge_shift := -1 if row_start > row_end else 1 + row_start += edge_shift + row_end += edge_shift + + var column_editor := column_editors[column_index] + for i in range(row_start, row_end, edge_shift): + var cur_cell := Vector2i(column_index, i) + var cur_cell_node := get_cell_node_from_position(cur_cell) + if cur_cell not in edited_cells: + edited_cells.append(cur_cell) + + var cur_cell_value = editor_view.io.get_value(editor_view.rows[cur_cell.y], editor_view.columns[cur_cell.x]) + var cur_cell_text : String = column_editor.to_text(cur_cell_value) + edited_cells_text.append(cur_cell_text) + edit_cursor_positions.append(cur_cell_text.length()) + + if cur_cell_node == null or !cur_cell_node.visible or cur_cell_node.mouse_filter == MOUSE_FILTER_IGNORE: + # When showing several classes, empty cells will be non-selectable. + continue + + column_editors[column_index].set_selected(cur_cell_node, true) + + _selection_changed() + + +func rightclick_cells(): + cells_rightclicked.emit(edited_cells) + + +func is_cell_node_selected(cell : Control) -> bool: + return get_cell_node_position(cell) in edited_cells + + +func is_cell_selected(cell : Vector2i) -> bool: + return cell in edited_cells + + +func can_select_cell(cell : Vector2i) -> bool: + if edited_cells.size() == 0: + return true + + if ( + get_cell_column(cell) + != get_cell_column(edited_cells[0]) + ): + return false + + return !cell in edited_cells + + +func get_cell_node_from_position(cell_pos : Vector2i) -> Control: + var cell_index := (cell_pos.y - editor_view.first_row) * editor_view.columns.size() + cell_pos.x + if cell_index < 0 or cell_index >= editor_view.node_table_root.get_child_count(): + return null + + return editor_view.node_table_root.get_child(cell_index) + + +func get_cell_node_position(cell : Control) -> Vector2i: + var col_count := editor_view.columns.size() + var cell_index := cell.get_index() + return Vector2i(cell_index % col_count, cell_index / col_count + editor_view.first_row) + + +func get_cell_column(cell : Vector2i) -> int: + return cell.x + + +func get_cell_row(cell : Vector2i) -> int: + return cell.y + + +func get_edited_rows() -> Array[int]: + var rows : Array[int] = [] + rows.resize(edited_cells.size()) + for i in rows.size(): + rows[i] = get_cell_row(edited_cells[i]) + + return rows + + +func clipboard_paste(): + if column_editors[edited_cells[0].x].is_text(): + editor_view.set_edited_cells_values( + TextEditingUtilsClass.multi_paste( + edited_cells_text, + edit_cursor_positions, + ) + ) + + elif DisplayServer.clipboard_has(): + var values := [] + values.resize(edited_cells.size()) + var pasted_lines := DisplayServer.clipboard_get().replace("\r", "").split("\n") + var paste_each_line := pasted_lines.size() == values.size() + + for i in values.size(): + values[i] = str_to_var( + pasted_lines[i] if paste_each_line else DisplayServer.clipboard_get() + ) + + editor_view.set_edited_cells_values(values) + + +func _selection_changed(): + queue_redraw() + cells_selected.emit(edited_cells) + + +func _set_visible_selected(state : bool): + for x in edited_cells: + var cell_node := get_cell_node_from_position(x) + if cell_node != null: + column_editors[get_cell_column(x)].set_selected(cell_node, state) + + +func _add_cell_to_selection(cell : Vector2i): + edited_cells.append(cell) + + var column_editor := column_editors[get_cell_column(cell)] + var cell_node := get_cell_node_from_position(cell) + if cell_node != null: + column_editor.set_selected(cell_node, true) + + var cell_value = editor_view.io.get_value(editor_view.rows[cell.y], editor_view.columns[cell.x]) + var text_value : String = column_editor.to_text(cell_value) + edited_cells_text.append(text_value) + edit_cursor_positions.append(text_value.length()) + + +func _update_selected_cells_text(): + if edited_cells_text.size() == 0: + return + + var column_editor := column_editors[get_cell_column(edited_cells[0])] + if !column_editor.text_update_on_edit(): + return + + for i in edited_cells.size(): + edited_cells_text[i] = column_editor.to_text(editor_view.io.get_value( + editor_view.rows[edited_cells[i].y], + editor_view.columns[edited_cells[i].x], + )) + edit_cursor_positions[i] = edited_cells_text[i].length() + + +func _try_open_docks(cell : Vector2i): + var column_index := get_cell_column(cell) + var row = editor_view.rows[get_cell_row(cell)] + var column := editor_view.columns[column_index] + var type := editor_view.column_types[column_index] + var hints := editor_view.column_hints[column_index] + + for x in node_property_editors.get_children(): + x.visible = x.try_edit_value(editor_view.io.get_value(row, column), type, hints) + x.get_node(x.path_property_name).text = column + + +func _on_inspector_property_edited(property : String): + if !editor_view.is_visible_in_tree(): return + if inspector_resource != editor_view.editor_plugin.get_editor_interface().get_inspector().get_edited_object(): + return + + if editor_view.columns[get_cell_column(edited_cells[0])] != property: + var columns := editor_view.columns + var previously_edited := edited_cells.duplicate() + var new_column := columns.find(property) + deselect_all_cells() + for i in previously_edited.size(): + _add_cell_to_selection(Vector2i(new_column, previously_edited[i].y)) + + var values := [] + values.resize(edited_cells.size()) + values.fill(inspector_resource[property]) + + editor_view.set_edited_cells_values.call_deferred(values) + _try_open_docks(edited_cells[0]) diff --git a/addons/resources_spreadsheet_view/main_screen/selection_manager.gd.uid b/addons/resources_spreadsheet_view/main_screen/selection_manager.gd.uid new file mode 100644 index 0000000..c4df49e --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/selection_manager.gd.uid @@ -0,0 +1 @@ +uid://b1ejnljj24ar2 diff --git a/addons/resources_spreadsheet_view/main_screen/table_header.gd b/addons/resources_spreadsheet_view/main_screen/table_header.gd new file mode 100644 index 0000000..7a8c56f --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/table_header.gd @@ -0,0 +1,72 @@ +@tool +extends HBoxContainer + +var manager : Control + + +func set_label(label : String): + $"Button".text = label.capitalize() + $"Button".tooltip_text = label + "\nClick to sort." + + +func _ready(): + $"Button".gui_input.connect(_on_main_gui_input) + $"Button2".about_to_popup.connect(_on_about_to_popup) + $"Button2".get_popup().id_pressed.connect(_on_list_id_pressed) + + +func _on_about_to_popup(): + var menu_popup : PopupMenu = $"Button2".get_popup() + menu_popup.clear() + menu_popup.add_item("Select All", 0) + menu_popup.add_item("Hide", 1) + + if !manager.editor_view.column_can_solo_open(get_index()): + menu_popup.add_item("(not a Resource property)", 2) + menu_popup.set_item_disabled(2, true) + menu_popup.add_separator("", 3) + + else: + menu_popup.add_item("Open Sub-Resources of Column", 2) + + if manager.editor_view.get_edited_cells_values().size() == 0 or manager.editor_view.get_selected_column() != get_index(): + menu_popup.add_item("(none selected)", 3) + menu_popup.set_item_disabled(3, true) + + else: + menu_popup.add_item("Open Sub-Resources in Selection", 3) + + +func _on_main_gui_input(event : InputEvent): + if event is InputEventMouseButton and event.pressed: + var popup : Popup = $"Button2".get_popup() + if event.button_index == MOUSE_BUTTON_RIGHT: + _on_about_to_popup() + popup.visible = !popup.visible + popup.size = Vector2.ZERO + popup.position = Vector2i(get_global_mouse_position()) + get_viewport().position + + else: + popup.visible = false + + +func _on_list_id_pressed(id : int): + match id: + 0: + manager.select_column(get_index()) + 1: + manager.hide_column(get_index()) + 2: + manager.editor_view.column_solo_open(get_index()) + 3: + var resources_to_open_unique := {} + for x in manager.editor_view.get_edited_cells_values(): + if x is Array: + for y in x: + resources_to_open_unique[y] = true + + if x is Resource: + resources_to_open_unique[x] = true + + if resources_to_open_unique.size() > 0: + manager.editor_view.display_resources(resources_to_open_unique.keys()) diff --git a/addons/resources_spreadsheet_view/main_screen/table_header.gd.uid b/addons/resources_spreadsheet_view/main_screen/table_header.gd.uid new file mode 100644 index 0000000..c983cda --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/table_header.gd.uid @@ -0,0 +1 @@ +uid://cei3tybsvg6r8 diff --git a/addons/resources_spreadsheet_view/main_screen/table_header.tscn b/addons/resources_spreadsheet_view/main_screen/table_header.tscn new file mode 100644 index 0000000..c287a34 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/table_header.tscn @@ -0,0 +1,23 @@ +[gd_scene load_steps=3 format=3 uid="uid://d1s6oihqedvo5"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/main_screen/table_header.gd" id="1_5fd1m"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="2_0ymob"] + +[node name="Header" type="HBoxContainer"] +offset_right = 179.0 +offset_bottom = 31.0 +size_flags_horizontal = 3 +script = ExtResource("1_5fd1m") + +[node name="Button" type="Button" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +text = "resource_name" +clip_text = true + +[node name="Button2" type="MenuButton" parent="."] +layout_mode = 2 +size_flags_horizontal = 9 +script = ExtResource("2_0ymob") +icon_name = "ArrowDown" diff --git a/addons/resources_spreadsheet_view/main_screen/table_pages.gd b/addons/resources_spreadsheet_view/main_screen/table_pages.gd new file mode 100644 index 0000000..3cfb0e4 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/table_pages.gd @@ -0,0 +1,118 @@ +@tool +extends HBoxContainer + +@onready var node_editor_view_root : Control = $"../../../.." + +var rows_per_page := 50 +var current_page := 0 + + +func update_page_count(array : Array) -> int: + var page_count : int = (node_editor_view_root.rows.size() - 1) / rows_per_page + 1 + node_editor_view_root.first_row = min(current_page, page_count) * rows_per_page + node_editor_view_root.last_row = min(node_editor_view_root.first_row + rows_per_page, array.size()) + return page_count + + +func _on_grid_updated(): + if node_editor_view_root.rows.size() == 0: + return + + visible = true + var page_count := update_page_count(node_editor_view_root.rows) + var pagelist_node := $"Scroll/Pagelist" + for x in pagelist_node.get_children(): + x.queue_free() + + var button_group := ButtonGroup.new() + var btns := [] + btns.resize(page_count) + for i in page_count: + var btn := Button.new() + btns[i] = btn + btn.toggle_mode = true + btn.button_group = button_group + btn.text = str(i + 1) + btn.pressed.connect(_on_button_pressed.bind(btn)) + btn.size_flags_vertical = SIZE_SHRINK_CENTER + pagelist_node.add_child(btn) + + var pagelist_line := HSeparator.new() + pagelist_line.size_flags_horizontal = SIZE_EXPAND_FILL + pagelist_node.add_child(pagelist_line) + btns[current_page].button_pressed = true + + var sort_property : StringName = node_editor_view_root.sorting_by + if sort_property == "": sort_property = "resource_path" + var sort_type : int = node_editor_view_root.column_types[node_editor_view_root.columns.find(sort_property)] + var property_values := [] + property_values.resize(page_count) + if(node_editor_view_root.rows.size() == 0): + return + + for i in page_count: + property_values[i] = node_editor_view_root.rows[i * rows_per_page].get(sort_property) + + if sort_type == TYPE_FLOAT or sort_type == TYPE_INT: + for i in page_count: + btns[i].text = str(property_values[i]) + + elif sort_type == TYPE_COLOR: + for i in page_count: + btns[i].self_modulate = property_values[i] * 0.75 + Color(0.25, 0.25, 0.25, 1.0) + + elif sort_type == TYPE_STRING: + var strings := [] + strings.resize(page_count) + for i in page_count: + strings[i] = property_values[i].get_file() + if strings[i] == "": + strings[i] = str(i) + + _fill_buttons_with_prefixes(btns, strings, page_count) + + elif sort_type == TYPE_OBJECT: + var strings := [] + strings.resize(page_count + 1) + for i in page_count: + if is_instance_valid(property_values[i]): + strings[i] = property_values[i].resource_path.get_file() + + _fill_buttons_with_prefixes(btns, strings, page_count) + + +func _fill_buttons_with_prefixes(btns : Array, strings : Array, page_count : int): + for i in page_count: + if strings[i] == null: + continue + + if i == 0: + btns[0].text = strings[0][0] + continue + + for j in strings[i].length(): + if strings[i].unicode_at(j) != strings[i - 1].unicode_at(j): + btns[i].text = strings[i].left(j + 1) + btns[i - 1].text = strings[i - 1].left(max(j + 1, btns[i - 1].text.length())) + break + + for i in page_count - 1: + btns[i].text = btns[i].text + "-" + btns[i + 1].text + + btns[page_count - 1].text += "-[End]" + + +func _on_button_pressed(button): + button.button_pressed = true + current_page = button.get_index() + _update_view() + + +func _on_LineEdit_value_changed(value): + rows_per_page = value + current_page = 0 + _update_view() + + +func _update_view(): + node_editor_view_root.refresh(false) diff --git a/addons/resources_spreadsheet_view/main_screen/table_pages.gd.uid b/addons/resources_spreadsheet_view/main_screen/table_pages.gd.uid new file mode 100644 index 0000000..64bc745 --- /dev/null +++ b/addons/resources_spreadsheet_view/main_screen/table_pages.gd.uid @@ -0,0 +1 @@ +uid://c7i31g52djr5x diff --git a/addons/resources_spreadsheet_view/plugin.cfg b/addons/resources_spreadsheet_view/plugin.cfg new file mode 100644 index 0000000..ec06e33 --- /dev/null +++ b/addons/resources_spreadsheet_view/plugin.cfg @@ -0,0 +1,9 @@ +[plugin] + +name="Edit Resources as Table" +description="Edit Many Resources from one Folder as a table. + +Heavily inspired by Multi-Cursor-Editing in text editors, so after selecting multiple cells (in the same column!) using Ctrl+Click or Shift+Click, most Basic-to-Intermediate movements should be available." +author="Don Tnowe" +version="2.7" +script="plugin.gd" diff --git a/addons/resources_spreadsheet_view/plugin.gd b/addons/resources_spreadsheet_view/plugin.gd new file mode 100644 index 0000000..70549be --- /dev/null +++ b/addons/resources_spreadsheet_view/plugin.gd @@ -0,0 +1,43 @@ +@tool +extends EditorPlugin + +var editor_view : Control +var undo_redo : EditorUndoRedoManager + + +func _enter_tree() -> void: + editor_view = load(get_script().resource_path.get_base_dir() + "/editor_view.tscn").instantiate() + editor_view.editor_interface = get_editor_interface() + if editor_view.editor_interface == null: + # 4.2: now a singleton + editor_view.editor_interface = Engine.get_singleton("EditorInterface") + + editor_view.editor_plugin = self + undo_redo = get_undo_redo() + get_editor_interface().get_editor_main_screen().add_child(editor_view) + _make_visible(false) + + +func _exit_tree() -> void: + if is_instance_valid(editor_view): + editor_view.queue_free() + + +func _get_plugin_name(): + return "ResourceTables" + + +func _make_visible(visible): + if is_instance_valid(editor_view): + editor_view.visible = visible + if visible: + editor_view.display_folder(editor_view.current_path) + + +func _has_main_screen(): + return true + + +func _get_plugin_icon(): + # Until I add an actual icon, this'll do. + return get_editor_interface().get_base_control().get_theme_icon("VisualShaderNodeComment", "EditorIcons") diff --git a/addons/resources_spreadsheet_view/plugin.gd.uid b/addons/resources_spreadsheet_view/plugin.gd.uid new file mode 100644 index 0000000..6004066 --- /dev/null +++ b/addons/resources_spreadsheet_view/plugin.gd.uid @@ -0,0 +1 @@ +uid://c1n7lygk7espv diff --git a/addons/resources_spreadsheet_view/settings_grid.gd b/addons/resources_spreadsheet_view/settings_grid.gd new file mode 100644 index 0000000..ba242a9 --- /dev/null +++ b/addons/resources_spreadsheet_view/settings_grid.gd @@ -0,0 +1,39 @@ +@tool +extends GridContainer + +const PREFIX := "addons/resources_spreadsheet_view/" + + +func _ready(): + ProjectSettings.set_setting(PREFIX + "array_color_tint", 100.0 if ProjectSettings.get_setting(PREFIX + "color_arrays", true) else 0.0) + ProjectSettings.set_setting(PREFIX + "color_arrays", null) + + for x in get_children(): + var setting : String = PREFIX + x.name.to_snake_case() + if x is CheckBox: + x.toggled.connect(_set_setting.bind(setting)) + if !ProjectSettings.has_setting(setting): + _set_setting(x.button_pressed, setting) + + else: + x.button_pressed = ProjectSettings.get_setting(setting) + + elif x is OptionButton: + x.item_selected.connect(_set_setting.bind(setting)) + if !ProjectSettings.has_setting(setting): + _set_setting(x.selected, setting) + + else: + x.selected = ProjectSettings.get_setting(setting) + + elif x is Range: + x.value_changed.connect(_set_setting.bind(setting)) + if !ProjectSettings.has_setting(setting): + _set_setting(x.value, setting) + + else: + x.value = ProjectSettings.get_setting(setting) + + +func _set_setting(new_value, setting : String): + ProjectSettings.set_setting(setting, new_value) diff --git a/addons/resources_spreadsheet_view/settings_grid.gd.uid b/addons/resources_spreadsheet_view/settings_grid.gd.uid new file mode 100644 index 0000000..21ff194 --- /dev/null +++ b/addons/resources_spreadsheet_view/settings_grid.gd.uid @@ -0,0 +1 @@ +uid://brbgjclrwpvee diff --git a/addons/resources_spreadsheet_view/settings_grid.tscn b/addons/resources_spreadsheet_view/settings_grid.tscn new file mode 100644 index 0000000..860aa9e --- /dev/null +++ b/addons/resources_spreadsheet_view/settings_grid.tscn @@ -0,0 +1,141 @@ +[gd_scene load_steps=2 format=3 uid="uid://dhunxgcae6h1"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/settings_grid.gd" id="1_s8s2f"] + +[node name="Settings" type="ScrollContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 8.0 +offset_top = 8.0 +offset_right = -622.0 +offset_bottom = -322.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="RichTextLabel" type="VBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="GridContainer" type="GridContainer" parent="RichTextLabel"] +layout_mode = 2 +columns = 2 +script = ExtResource("1_s8s2f") + +[node name="Label" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Color-type cells style rows" +autowrap_mode = 2 + +[node name="ColorRows" type="CheckBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +button_pressed = true +text = "Enable" + +[node name="Label2" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Collection item color tint" +autowrap_mode = 2 + +[node name="ArrayColorTint" type="SpinBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +value = 100.0 + +[node name="Label3" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Array cell min width" +autowrap_mode = 2 + +[node name="ArrayMinWidth" type="SpinBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +min_value = 32.0 +max_value = 512.0 +value = 128.0 + +[node name="Label8" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Resource preview size (Including Textures)" +autowrap_mode = 2 + +[node name="ResourcePreviewSize" type="SpinBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +min_value = 8.0 +max_value = 1024.0 +value = 32.0 + +[node name="Label7" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Clip header text (makes columns smaller)" +autowrap_mode = 2 + +[node name="ClipHeaders" type="CheckBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +text = "Enable" + +[node name="Label5" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Duplicate arrays on edit (slower, but can be undone)" +autowrap_mode = 2 + +[node name="DupeArrays" type="CheckBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +button_pressed = true +text = "Enable" + +[node name="Label6" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Show context menu on left-click (and not just rightclick)" +autowrap_mode = 2 + +[node name="ContextMenuOnLeftclick" type="CheckBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +text = "Enable" + +[node name="Label9" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Fold bottom docks on startup (drag their top bar to resize)" +autowrap_mode = 2 + +[node name="FoldDocks" type="CheckBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +button_pressed = true +text = "Enable" + +[node name="Label10" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Resources in cells (allow viewing _to_string() override's result)" +autowrap_mode = 2 + +[node name="ResourceCellLabelMode" type="OptionButton" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +toggle_mode = false +selected = 1 +allow_reselect = true +item_count = 3 +popup/item_0/text = "Name + ToString()" +popup/item_0/id = 3 +popup/item_1/text = "ToString()" +popup/item_1/id = 1 +popup/item_2/text = "Name Only" +popup/item_2/id = 2 + +[node name="Label11" type="Label" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Freeze/Lock First Column" +autowrap_mode = 2 + +[node name="FreezeFirstColumn" type="CheckBox" parent="RichTextLabel/GridContainer"] +layout_mode = 2 +button_pressed = true +text = "Enable" diff --git a/addons/resources_spreadsheet_view/text_editing_utils.gd b/addons/resources_spreadsheet_view/text_editing_utils.gd new file mode 100644 index 0000000..f81027c --- /dev/null +++ b/addons/resources_spreadsheet_view/text_editing_utils.gd @@ -0,0 +1,192 @@ +extends RefCounted + +const non_typing_paragraph := "¶" +const non_typing_space := "●" +const whitespace_chars := [ + 32, # " " + 44, # "," + 58, # ":" + 45, # "-" + 59, # ";" + 40, # "(" + 41, # ")" + 46, # "." + 182, # "¶" Linefeed + 10, # "\n" Actual Linefeed + 967, # "●" Whitespace +] + + +static func is_character_whitespace(text : String, idx : int) -> bool: + if idx <= 0: return true # Stop at the edges. + if idx >= text.length(): return true + return text.unicode_at(idx) in whitespace_chars + + +static func show_non_typing(text : String) -> String: + text = text\ + .replace(non_typing_paragraph, "\n")\ + .replace(non_typing_space, " ") + + if text.ends_with("\n"): + text = text.left(text.length() - 1) + non_typing_paragraph + + elif text.ends_with(" "): + text = text.left(text.length() - 1) + non_typing_space + + return text + + +static func revert_non_typing(text : String) -> String: + if text.ends_with(non_typing_paragraph): + text = text.left(text.length() - 1) + "\n" + + elif text.ends_with(non_typing_space): + text = text.left(text.length() - 1) + " " + + return text + + +static func get_caret_movement_from_key(keycode : int) -> int: + match keycode: + KEY_LEFT: + return -1 + KEY_RIGHT: + return +1 + KEY_HOME: + return -2 + KEY_END: + return +2 + + return 0 + + +static func multi_move_caret(offset : int, edited_cells_text : Array, edit_caret_positions : Array, whole_word : bool) -> bool: + if offset == -1: + for i in edit_caret_positions.size(): + edit_caret_positions[i] = _step_cursor(edited_cells_text[i], edit_caret_positions[i], -1, whole_word) + + elif offset == +1: + for i in edit_caret_positions.size(): + edit_caret_positions[i] = _step_cursor(edited_cells_text[i], edit_caret_positions[i], +1, whole_word) + + elif offset < -1: + for i in edit_caret_positions.size(): + edit_caret_positions[i] = 0 + + elif offset > +1: + for i in edit_caret_positions.size(): + edit_caret_positions[i] = edited_cells_text[i].length() + + return offset != 0 + + +static func multi_erase_right(values : Array, cursor_positions : Array, whole_word : bool): + for i in values.size(): + var start_pos : int = cursor_positions[i] + cursor_positions[i] = _step_cursor(values[i], cursor_positions[i], 1, whole_word) + + cursor_positions[i] = min( + cursor_positions[i], + values[i].length() + ) + values[i] = ( + values[i].left(start_pos) + + values[i].substr(cursor_positions[i]) + ) + cursor_positions[i] = start_pos + + return values + + +static func multi_erase_left(values : Array, cursor_positions : Array, whole_word : bool): + for i in values.size(): + var start_pos : int = cursor_positions[i] + + cursor_positions[i] = _step_cursor(values[i], cursor_positions[i], -1, whole_word) + values[i] = ( + values[i].substr(0, cursor_positions[i]) + + values[i].substr(start_pos) + ) + + return values + + +static func multi_paste(values : Array, cursor_positions : Array): + var pasted_lines := DisplayServer.clipboard_get().replace("\r", "").split("\n") + var paste_each_line := pasted_lines.size() == values.size() + + for i in values.size(): + if paste_each_line: + cursor_positions[i] += pasted_lines[i].length() + + else: + cursor_positions[i] += DisplayServer.clipboard_get().length() + + values[i] = ( + values[i].left(cursor_positions[i]) + + (pasted_lines[i] if paste_each_line else DisplayServer.clipboard_get()) + + values[i].substr(cursor_positions[i]) + ) + + return values + + +static func multi_copy(values : Array): + DisplayServer.clipboard_set("\n".join(values)) + + +static func multi_input(input_char : String, values : Array, cursor_positions : Array): + for i in values.size(): + values[i] = ( + values[i].left(cursor_positions[i]) + + input_char + + values[i].substr(cursor_positions[i]) + ) + cursor_positions[i] = min(cursor_positions[i] + 1, values[i].length()) + + return values + + +static func get_caret_rect(cell_text : String, caret_position : int, font : Font, font_size : int, label_padding_left : float, caret_width : float = 2.0) -> Rect2: + var font_height := font.get_height(font_size) + var char_size := Vector2(0, font_height) + var result_pos := Vector2(label_padding_left, 0) + for j in max(caret_position, 0) + 1: + if j == 0: continue + if cell_text.unicode_at(j - 1) == 10: + # If "\n" found, next line. + # The 2.0 is ACTUALLY not 2.0 and varies per character. + # Since get_char_size() does not return the correct size, this will cause problems with non-Latin characters + result_pos.x = label_padding_left + result_pos.y += font_height - 2.0 + font_height = 0.0 + continue + + char_size = font.get_char_size(cell_text.unicode_at(j - 1), font_size) + font_height = maxf(char_size.y, font_height) + result_pos.x += char_size.x + + return Rect2(result_pos + Vector2(1.0, 0.0), Vector2(caret_width, char_size.y)) + + +static func _step_cursor(text : String, start : int, step : int = 1, whole_word : bool = false) -> int: + var cur := start + if whole_word and is_character_whitespace(text, cur + step): + cur += step + + while true: + cur += step + if !whole_word or is_character_whitespace(text, cur): + if cur > text.length(): + return text.length() + + if cur <= 0: + return 0 + + if whole_word and step < 0: + return cur + 1 + + return cur + + return 0 diff --git a/addons/resources_spreadsheet_view/text_editing_utils.gd.uid b/addons/resources_spreadsheet_view/text_editing_utils.gd.uid new file mode 100644 index 0000000..da5338c --- /dev/null +++ b/addons/resources_spreadsheet_view/text_editing_utils.gd.uid @@ -0,0 +1 @@ +uid://cgmwf5hip0j0e diff --git a/addons/resources_spreadsheet_view/typed_cells/array.tscn b/addons/resources_spreadsheet_view/typed_cells/array.tscn new file mode 100644 index 0000000..61062ac --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/array.tscn @@ -0,0 +1,36 @@ +[gd_scene format=3 uid="uid://ydrs54md3knl"] + +[node name="Label" type="MarginContainer"] +offset_right = 16.0 +offset_bottom = 16.0 +size_flags_vertical = 9 +mouse_filter = 0 + +[node name="Box" type="HFlowContainer" parent="."] +layout_mode = 2 +mouse_filter = 2 + +[node name="Back" type="Control" parent="."] +show_behind_parent = true +layout_mode = 2 +mouse_filter = 2 + +[node name="ColorRect" type="ColorRect" parent="Back"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 1.0 +offset_top = 1.0 +offset_right = -1.0 +offset_bottom = -1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +color = Color(0.247059, 0.247059, 0.247059, 0.498039) + +[node name="Selected" type="ColorRect" parent="."] +visible = false +layout_mode = 2 +mouse_filter = 2 +color = Color(1, 1, 1, 0.247059) diff --git a/addons/resources_spreadsheet_view/typed_cells/basic.tscn b/addons/resources_spreadsheet_view/typed_cells/basic.tscn new file mode 100644 index 0000000..541f1ba --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/basic.tscn @@ -0,0 +1,33 @@ +[gd_scene format=3 uid="uid://cghfjg6qt3rb1"] + +[node name="Label" type="Label"] +offset_right = 20.0 +offset_bottom = 23.0 +size_flags_vertical = 9 +mouse_filter = 0 + +[node name="Back" type="ColorRect" parent="."] +show_behind_parent = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 1.0 +offset_top = 1.0 +offset_right = -1.0 +offset_bottom = -1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +color = Color(0.247059, 0.247059, 0.247059, 0.498039) + +[node name="Selected" type="ColorRect" parent="."] +visible = false +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +color = Color(1, 1, 1, 0.247059) diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor.gd new file mode 100644 index 0000000..c8a03f1 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor.gd @@ -0,0 +1,46 @@ +class_name ResourceTablesCellEditor +extends RefCounted + +const TextEditingUtilsClass := preload("res://addons/resources_spreadsheet_view/text_editing_utils.gd") + +const CELL_SCENE_DIR := "res://addons/resources_spreadsheet_view/typed_cells/" + +var hint_strings_array := [] + + +## Override to define where the cell should be shown. +func can_edit_value(value, type, property_hint, column_index) -> bool: + return value != null + +## Override to change how the cell is created; preload a scene or create nodes from code. +## Caller is an instance of [code]editor_view.tscn[/code]. +func create_cell(caller : Control) -> Control: + return load(CELL_SCENE_DIR + "basic.tscn").instantiate() + +## Override to change behaviour when the cell is clicked to be selected. +func set_selected(node : Control, selected : bool): + node.get_node("Selected").visible = selected + +## Override to change how the value is displayed. +func set_value(node : Control, value): + node.text = TextEditingUtilsClass.show_non_typing(str(value)) + +## Override to prevent the cell from being edited as text. +func is_text(): + return true + +## Override to refresh internal text values when edited using keyboard. +func text_update_on_edit(): + return false + +## Override to define custom behaviour for converting the value into text for editing and copy/paste. +func to_text(value) -> String: + return var_to_str(value) + +## Override to define custom behaviour for converting the value from text for editing and copy/paste. +func from_text(text : String): + return str_to_var(text) + +## Override to change behaviour when there are color cells to the left of this cell. +func set_color(node : Control, color : Color): + node.get_node("Back").modulate = color * 1.0 diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor.gd.uid new file mode 100644 index 0000000..31c53d3 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor.gd.uid @@ -0,0 +1 @@ +uid://crapu2hawruxu diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd new file mode 100644 index 0000000..1ddd939 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd @@ -0,0 +1,64 @@ +extends ResourceTablesCellEditor + +const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd") + + +func can_edit_value(value, type, property_hint, column_index) -> bool: + return type == TYPE_PACKED_STRING_ARRAY or type == TYPE_ARRAY + + +func create_cell(caller : Control) -> Control: + return load(CELL_SCENE_DIR + "array.tscn").instantiate() + + +func set_value(node : Control, value): + var children := node.get_node("Box").get_children() + node.custom_minimum_size.x = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "array_min_width") + var color_tint : float = 0.01 * ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "array_color_tint", 100.0) + var cell_label_mode : int = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "resource_cell_label_mode", 0) + while children.size() < value.size(): + children.append(Label.new()) + node.get_node("Box").add_child(children[children.size() - 1]) + + var column_hints = hint_strings_array[node.get_index() % hint_strings_array.size()] + for i in children.size(): + if i >= value.size(): + children[i].visible = false + + else: + children[i].visible = true + _write_value_to_child(value[i], value[i], column_hints, children[i], color_tint, cell_label_mode) + + +func _write_value_to_child(value, key, hint_arr : PackedStringArray, child : Label, color_tint : float, cell_label_mode : int): + if value is Resource: + value = _resource_to_string(value, cell_label_mode) + + if key is Resource: + key = _resource_to_string(key, cell_label_mode) + + child.text = str(value) + child.self_modulate = ( + Color.WHITE * (1.0 - color_tint) + + + (Color(str(key).hash()) + Color(0.2, 0.2, 0.2, 1.0)) * color_tint + ) + + +static func _resource_to_string(res : Resource, cell_label_mode : int): + var prefix := "" + if cell_label_mode != 2: + if res.has_method(&"_to_string"): + prefix = res._to_string() + "\n" + + elif res.has_method(&"ToString"): + prefix = res.ToString() + "\n" + + if cell_label_mode == 1 && !prefix.is_empty(): + return prefix.trim_suffix("\n") + + return prefix + (res.resource_name if res.resource_name != "" else "[%s]" % res.resource_path.get_file()) + + +func is_text(): + return false diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd.uid new file mode 100644 index 0000000..e30d28e --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd.uid @@ -0,0 +1 @@ +uid://dr4uembien5bu diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd new file mode 100644 index 0000000..4848b71 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd @@ -0,0 +1,34 @@ +extends ResourceTablesCellEditor + + +func can_edit_value(value, type, property_hint, column_index) -> bool: + return type == TYPE_BOOL + + +func set_value(node : Control, value): + if value is bool: + _set_value_internal(node, value) + + else: + _set_value_internal(node, node.text.begins_with("O")) + + +func _set_value_internal(node, value): + node.text = "ON" if value else "off" + node.self_modulate.a = 1.0 if value else 0.2 + + +func text_update_on_edit(): + return true + + +func to_text(value) -> String: + return "ON" if value else "off" + + +func from_text(text : String): + if text.begins_with("O"): + return text == "ON" + + else: + return text != "off" diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd.uid new file mode 100644 index 0000000..7d7bdce --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_bool.gd.uid @@ -0,0 +1 @@ +uid://cldpo8febdypl diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd new file mode 100644 index 0000000..019a1f2 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd @@ -0,0 +1,43 @@ +extends ResourceTablesCellEditor + +var _cached_color := Color.WHITE + + +func create_cell(caller : Control) -> Control: + var node : Label = load(CELL_SCENE_DIR + "basic.tscn").instantiate() + var color := ColorRect.new() + node.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT + node.custom_minimum_size.x = 56 + node.add_child(color) + color.name = "Color" + _resize_color_rect.call_deferred(color) + return node + + +func _resize_color_rect(rect): + if !is_instance_valid(rect): return # Table refreshed twice, probably? Either way, this fix is easier + rect.size = Vector2(8, 0) + rect.set_anchors_and_offsets_preset(Control.PRESET_LEFT_WIDE, Control.PRESET_MODE_KEEP_WIDTH) + + +func can_edit_value(value, type, property_hint, property_hint_string) -> bool: + return type == TYPE_COLOR + + +func set_value(node : Control, value): + if value is String: + node.text = TextEditingUtilsClass.show_non_typing(str(value)) + + else: + node.text = value.to_html(true) + _cached_color = value + + node.get_node("Color").color = value + + +func to_text(value) -> String: + return value.to_html() + + +func from_text(text : String): + return Color.from_string(text, Color.BLACK) diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd.uid new file mode 100644 index 0000000..e59257f --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_color.gd.uid @@ -0,0 +1 @@ +uid://bpbynwaamkt2l diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd new file mode 100644 index 0000000..cec4702 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd @@ -0,0 +1,51 @@ +extends "res://addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd" + + +func can_edit_value(value, type, property_hint, column_index) -> bool: + return type == TYPE_DICTIONARY + + +func create_cell(caller : Control) -> Control: + return load(CELL_SCENE_DIR + "array.tscn").instantiate() + + +func set_value(node : Control, value): + var children := node.get_node("Box").get_children() + node.custom_minimum_size.x = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "array_min_width") + var color_tint : float = 0.01 * ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "array_color_tint", 100.0) + var cell_label_mode : int = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "resource_cell_label_mode", 0) + while children.size() < value.size(): + children.append(Label.new()) + node.get_node("Box").add_child(children[children.size() - 1]) + + var column_hints : PackedStringArray = hint_strings_array[node.get_index() % hint_strings_array.size()] + var values : Array = value.values() + var keys : Array = value.keys() + + for i in children.size(): + if i >= values.size(): + children[i].visible = false + + else: + children[i].visible = true + var current_value = values[i] + var current_key = keys[i] + if current_value is Resource: + current_value = _resource_to_string(current_value, cell_label_mode) + + if current_key is Resource: + current_key = _resource_to_string(current_key, cell_label_mode) + + _write_value_to_child("%s ◆ %s" % [current_key, current_value], current_key, column_hints, children[i], color_tint, cell_label_mode) + + +func is_text(): + return false + + +func to_text(value) -> String: + return var_to_str(value).replace("\n", " ") + + +func from_text(text : String): + return str_to_var(text) diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd.uid new file mode 100644 index 0000000..228018f --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_dict.gd.uid @@ -0,0 +1 @@ +uid://datu2k5p56vo4 diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd new file mode 100644 index 0000000..e05f5ce --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd @@ -0,0 +1,38 @@ +extends ResourceTablesCellEditor + + +func can_edit_value(value, type, property_hint, column_index) -> bool: + return type == TYPE_INT and property_hint == PROPERTY_HINT_ENUM + + +func set_value(node : Control, value): + if value == null: + # Sometimes, when creating new property, becomes null + value = 0 + + var value_str : String + var key_found := -1 + var hint_arr : Array = hint_strings_array[node.get_index() % hint_strings_array.size()] + for i in hint_arr.size(): + var colon_found : int = hint_arr[i].rfind(":") + if colon_found == -1: + key_found = value + break + + if hint_arr[i].substr(colon_found + 1).to_int() == value: + key_found = i + break + + if key_found != -1 and key_found < hint_arr.size(): + value_str = hint_arr[key_found] + + else: + value_str = "?:%s" % value + + node.text = value_str + node.self_modulate = Color(node.text.hash()) + Color(0.25, 0.25, 0.25, 1.0) + node.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + + +func is_text(): + return false diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd.uid new file mode 100644 index 0000000..7446e5c --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum.gd.uid @@ -0,0 +1 @@ +uid://ppk35uodjlbu diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd new file mode 100644 index 0000000..c9d19fb --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd @@ -0,0 +1,39 @@ +extends "res://addons/resources_spreadsheet_view/typed_cells/cell_editor_array.gd" + + +func can_edit_value(value, type, property_hint, column_index) -> bool: + if ( + type != TYPE_PACKED_INT32_ARRAY + and type != TYPE_PACKED_INT64_ARRAY + and type != TYPE_ARRAY + ) or property_hint != PROPERTY_HINT_TYPE_STRING: + return false + + return hint_strings_array[column_index][0].begins_with("2/2:") + + +func _write_value_to_child(value, key, hint_arr : PackedStringArray, child : Label, color_tint : float, cell_label_mode : int): + var value_str : String + var key_found := -1 + for i in hint_arr.size(): + var colon_found := hint_arr[i].rfind(":") + if colon_found == -1: + key_found = value + break + + if hint_arr[i].substr(colon_found + 1).to_int() == value: + key_found = i + break + + if key_found == 0: + # Enum array hints have "2/3:" before list. + var found := hint_arr[0].find(":") + 1 + value_str = hint_arr[0].substr(hint_arr[0].find(":") + 1) + + elif key_found != -1: + value_str = hint_arr[key_found] + + else: + value_str = "?:%s" % value + + super(value_str, value_str, hint_arr, child, color_tint, cell_label_mode) diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd.uid new file mode 100644 index 0000000..4e3b0e9 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_enum_array.gd.uid @@ -0,0 +1 @@ +uid://c7gro0k73cug0 diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd new file mode 100644 index 0000000..4f00833 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd @@ -0,0 +1,13 @@ +extends ResourceTablesCellEditor + + +func can_edit_value(value, type, property_hint, column_index) -> bool: + return type == TYPE_FLOAT or type == TYPE_INT + + +func to_text(value) -> String: + return str(value) + + +func from_text(text : String): + return text.to_float() diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd.uid new file mode 100644 index 0000000..d56b3ef --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_number.gd.uid @@ -0,0 +1 @@ +uid://b5jx1oywhxeur diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd new file mode 100644 index 0000000..e2a170f --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd @@ -0,0 +1,73 @@ +extends ResourceTablesCellEditor + +const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd") + +var previewer : EditorResourcePreview + + +func can_edit_value(value, type, property_hint, column_index) -> bool: + return type == TYPE_OBJECT + + +func create_cell(caller : Control) -> Control: + if previewer == null: + previewer = caller.editor_plugin.get_editor_interface().get_resource_previewer() + + var node = load(CELL_SCENE_DIR + "resource.tscn").instantiate() + return node + + +func set_value(node : Control, value): + var preview_node := node.get_node("Box/Tex") + var label_node := node.get_node("Box/Label") + if value == null: + preview_node.visible = false + label_node.text = "[empty]" + node.editor_description = "" + + if !value is Resource: return + + node.editor_description = value.resource_path + label_node.text = _resource_to_string(value, ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "resource_cell_label_mode", 0)) + + if value is Texture: + preview_node.visible = true + preview_node.texture = value + + else: + preview_node.visible = false + previewer.queue_resource_preview(value.resource_path, self, &"_on_preview_loaded", node) + + preview_node.custom_minimum_size = Vector2.ONE * ProjectSettings.get_setting( + TablesPluginSettingsClass.PREFIX + "resource_preview_size" + ) + + +func set_color(node : Control, color : Color): + node.get_node("Back").modulate = color * 0.6 if node.editor_description == "" else color + + +func is_text(): + return false + + +func _on_preview_loaded(path : String, preview : Texture, thumbnail_preview : Texture, node): + # Abort if the node has been deleted since. + if is_instance_valid(node): + node.get_node("Box/Tex").visible = true + node.get_node("Box/Tex").texture = preview + + +static func _resource_to_string(res : Resource, cell_label_mode : int): + var prefix := "" + if cell_label_mode != 2: + if res.has_method(&"_to_string"): + prefix = res._to_string() + "\n" + + elif res.has_method(&"ToString"): + prefix = res.ToString() + "\n" + + if cell_label_mode == 1 && !prefix.is_empty(): + return prefix.trim_suffix("\n") + + return prefix + (res.resource_name if res.resource_name != "" else "[%s]" % res.resource_path.get_file()) diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd.uid new file mode 100644 index 0000000..735f104 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_resource.gd.uid @@ -0,0 +1 @@ +uid://b5rc3fp0kvuml diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd b/addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd new file mode 100644 index 0000000..5a56501 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd @@ -0,0 +1,13 @@ +extends ResourceTablesCellEditor + + +func to_text(value) -> String: + return str(value) + + +func from_text(text : String): + return text + + +func set_color(node : Control, color : Color): + node.get_node("Back").modulate = color * 0.6 diff --git a/addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd.uid b/addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd.uid new file mode 100644 index 0000000..7e05e11 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/cell_editor_string.gd.uid @@ -0,0 +1 @@ +uid://d1ycolpe65yel diff --git a/addons/resources_spreadsheet_view/typed_cells/resource.tscn b/addons/resources_spreadsheet_view/typed_cells/resource.tscn new file mode 100644 index 0000000..1372d02 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_cells/resource.tscn @@ -0,0 +1,45 @@ +[gd_scene format=3 uid="uid://clcndgxaty503"] + +[node name="Label" type="MarginContainer"] +size_flags_vertical = 9 +mouse_filter = 0 + +[node name="Back" type="Control" parent="."] +show_behind_parent = true +layout_mode = 2 +mouse_filter = 2 + +[node name="ColorRect" type="ColorRect" parent="Back"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 1.0 +offset_top = 1.0 +offset_right = -2.0 +offset_bottom = -1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +color = Color(0.247059, 0.247059, 0.247059, 0.498039) + +[node name="Selected" type="ColorRect" parent="."] +visible = false +layout_mode = 2 +mouse_filter = 2 +color = Color(1, 1, 1, 0.247059) + +[node name="Box" type="HBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 2 + +[node name="Tex" type="TextureRect" parent="Box"] +layout_mode = 2 +mouse_filter = 2 +expand_mode = 1 +stretch_mode = 5 + +[node name="Label" type="Label" parent="Box"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "res.tres" diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_array.gd b/addons/resources_spreadsheet_view/typed_editors/dock_array.gd new file mode 100644 index 0000000..bd5270b --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_array.gd @@ -0,0 +1,252 @@ +@tool +extends ResourceTablesDockEditor + +@onready var recent_container := $"HBoxContainer/Control2/HBoxContainer/HFlowContainer" +@onready var contents_label := $"HBoxContainer/HBoxContainer/Panel/Label" +@onready var button_box := $"HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer" +@onready var value_input := $"HBoxContainer/HBoxContainer/Control/VBoxContainer/LineEdit" + +var _stored_value +var _stored_type := 0 + + +func _ready(): + super() + contents_label.text_changed.connect(_on_contents_edit_text_changed) + + +func try_edit_value(value, type, property_hint) -> bool: + if ( + type != TYPE_ARRAY and type != TYPE_PACKED_STRING_ARRAY + and type != TYPE_PACKED_INT32_ARRAY and type != TYPE_PACKED_FLOAT32_ARRAY + and type != TYPE_PACKED_INT64_ARRAY and type != TYPE_PACKED_FLOAT64_ARRAY + ): + return false + + if sheet.column_hint_strings[sheet.get_selected_column()][0].begins_with("2/2:"): + # For enums, prefer the specialized dock. + return false + + _stored_type = type + _stored_value = value.duplicate() # Generic arrays are passed by reference + contents_label.text = str(value) + + var is_generic_array : bool = _stored_type == TYPE_ARRAY and !value.is_typed() + button_box.get_child(1).visible = ( + is_generic_array or value.get_typed_builtin() == TYPE_STRING or value.get_typed_builtin() == TYPE_STRING_NAME + or _stored_type == TYPE_PACKED_STRING_ARRAY + ) + button_box.get_child(2).visible = ( + is_generic_array or value.get_typed_builtin() == TYPE_INT + or _stored_type == TYPE_PACKED_INT32_ARRAY or _stored_type == TYPE_PACKED_INT64_ARRAY + ) + button_box.get_child(3).visible = ( + is_generic_array or value.get_typed_builtin() == TYPE_FLOAT + or _stored_type == TYPE_PACKED_FLOAT32_ARRAY or _stored_type == TYPE_PACKED_FLOAT64_ARRAY + ) + button_box.get_child(5).visible = ( + is_generic_array or value.get_typed_builtin() == TYPE_OBJECT + ) + + if value.get_typed_builtin() == TYPE_OBJECT: + if !value_input is EditorResourcePicker: + var new_input : EditorResourcePicker = load("res://addons/resources_spreadsheet_view/editor_resource_array_picker.gd").new() + new_input.size_flags_horizontal = SIZE_EXPAND_FILL + new_input.base_type = value.get_typed_class_name() + new_input.on_resources_dropped.connect(func(p): + _add_values(p) + for x in p: + _add_recent(x) + ) + new_input.resource_selected.connect(func(p1, p2): EditorInterface.edit_resource(p1)) + + value_input.replace_by(new_input) + value_input.free() + value_input = new_input + + else: + if !value_input is LineEdit: + var new_input := LineEdit.new() + new_input.size_flags_horizontal = SIZE_EXPAND_FILL + + value_input.replace_by(new_input) + value_input.free() + value_input = new_input + + return true + + +func _add_value(value): + _stored_value.append(value) + var values : Array = sheet.get_edited_cells_values() + var cur_value + var dupe_array : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_array: + cur_value = cur_value.duplicate() + + cur_value.append(value) + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _add_values(added_values : Array): + _stored_value.append_array(added_values) + var values : Array = sheet.get_edited_cells_values() + var cur_value + var dupe_array : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_array: + cur_value = cur_value.duplicate() + + cur_value.append_array(added_values) + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _remove_value(value): + _stored_value.remove_at(_stored_value.find(value)) + var values : Array = sheet.get_edited_cells_values() + var cur_value : Array + var dupe_array : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_array: + cur_value = cur_value.duplicate() + + if cur_value.has(value): # erase() not defined in PoolArrays + cur_value.remove_at(cur_value.find(value)) + + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _add_recent(value): + for x in recent_container.get_children(): + if x.text == str(value): + return + + if value is Resource and x.tooltip_text == value.resource_path: + return + + var node := Button.new() + var value_str : String = str(value) + if value is Resource: + value_str = value.resource_path.get_file() if value.resource_name == "" else value.resource_name + node.tooltip_text = value.resource_path + + node.text = value_str + node.self_modulate = Color(value_str.hash()) + Color(0.25, 0.25, 0.25, 1.0) + node.pressed.connect(_on_recent_clicked.bind(node, value)) + recent_container.add_child(node) + + +func _on_recent_clicked(button : Button, value): + var recent_mode : int = recent_container.get_child(1).selected + if value_input is EditorResourcePicker: + value_input.edited_resource = value + + else: + value_input.text = str(value) + + if recent_mode == 0: + _add_value(value) + + if recent_mode == 1: + _remove_value(value) + + if recent_mode == 2: + button.queue_free() + + +func _on_Remove_pressed(): + if value_input is EditorResourcePicker: + _remove_value(value_input.edited_resource) + + elif str_to_var(value_input.text) != null: + _remove_value(str_to_var(value_input.text)) + + else: + _remove_value(value_input.text) + + +func _on_RemoveLast_pressed(): + _stored_value.pop_back() + var values : Array = sheet.get_edited_cells_values() + var cur_value : Array + var dupe_array : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_array: + cur_value = cur_value.duplicate() + + cur_value.pop_back() + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _on_ClearRecent_pressed(): + for i in recent_container.get_child_count(): + if i == 0: continue + recent_container.get_child(i).free() + + +func _on_Float_pressed(): + _add_value(value_input.text.to_float()) + + +func _on_Int_pressed(): + _add_value(value_input.text.to_int()) + + +func _on_String_pressed(): + _add_value(value_input.text) + _add_recent(value_input.text) + + +func _on_Variant_pressed(): + if value_input is EditorResourcePicker: + _add_value(value_input.edited_resource) + + else: + _add_value(str_to_var(value_input.text)) + + +func _on_Resource_pressed(): + var new_value + if value_input is LineEdit: + new_value = load(value_input.text) + + elif value_input is EditorResourcePicker: + new_value = value_input.edited_resource + + _add_value(new_value) + _add_recent(new_value) + + +func _on_AddRecentFromSel_pressed(): + for x in sheet.get_edited_cells_values(): + for y in x: + _add_recent(y) + + +func _on_contents_edit_text_changed(): + var value = str_to_var(contents_label.text) + if !value is Array: + return + + var values : Array = sheet.get_edited_cells_values() + for i in values.size(): + values[i] = values[i].duplicate() + values[i].resize(value.size()) + for j in value.size(): + values[i][j] = value[j] + + _stored_value = value + sheet.set_edited_cells_values(values) diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_array.gd.uid b/addons/resources_spreadsheet_view/typed_editors/dock_array.gd.uid new file mode 100644 index 0000000..8703323 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_array.gd.uid @@ -0,0 +1 @@ +uid://bjxk53g4x27dx diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_array.tscn b/addons/resources_spreadsheet_view/typed_editors/dock_array.tscn new file mode 100644 index 0000000..0fd2cbf --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_array.tscn @@ -0,0 +1,195 @@ +[gd_scene load_steps=5 format=3 uid="uid://c3a2cip8ffccv"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_editors/dock_array.gd" id="1"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="2"] + +[sub_resource type="Image" id="Image_3slrg"] +data = { +"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 93, 93, 55, 255, 97, 97, 58, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 98, 98, 47, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 94, 94, 46, 255, 93, 93, 236, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id="ImageTexture_3oshq"] +image = SubResource("Image_3slrg") + +[node name="EditArray" type="VBoxContainer"] +anchors_preset = 10 +anchor_right = 1.0 +grow_horizontal = 2 +mouse_filter = 0 +script = ExtResource("1") + +[node name="Header" type="HBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 9 + +[node name="HBoxContainer" type="HBoxContainer" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Header/HBoxContainer"] +layout_mode = 2 +text = "EDIT: Array" + +[node name="HSeparator" type="HSeparator" parent="Header/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="Label" type="Label" parent="Header"] +layout_mode = 2 +text = "PROPERTY NAME" + +[node name="HSeparator2" type="HSeparator" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="HBoxContainer" type="HSplitContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +split_offset = 380 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer"] +layout_mode = 2 +alignment = 2 + +[node name="Panel" type="MarginContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="TextEdit" parent="HBoxContainer/HBoxContainer/Panel"] +layout_mode = 2 +size_flags_vertical = 5 +text = "[]" + +[node name="VSeparator2" type="VSeparator" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="Control" type="MarginContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer/HBoxContainer/Control"] +layout_mode = 2 + +[node name="LineEdit" type="LineEdit" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 +placeholder_text = "Input value to add/erase..." +clear_button_enabled = true + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Add:" + +[node name="String" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Add string" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "String" + +[node name="Int" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Add integer" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "int" + +[node name="Float" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Add float" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "float" + +[node name="Variant" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Guess type and add" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "Variant" + +[node name="Object" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Add resource (by path if string)" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "Object" + +[node name="Label2" type="Label" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Erase:" + +[node name="Remove" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Find and erase value in textbox" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "Remove" + +[node name="Remove2" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Remove last value" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "MoveLeft" + +[node name="VSeparator" type="VSeparator" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="Control2" type="ScrollContainer" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +follow_focus = true +horizontal_scroll_mode = 0 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/Control2"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +alignment = 2 + +[node name="VSeparator2" type="VSeparator" parent="HBoxContainer/Control2/HBoxContainer"] +layout_mode = 2 + +[node name="HFlowContainer" type="HFlowContainer" parent="HBoxContainer/Control2/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +text = "Recent:" + +[node name="OptionButton" type="OptionButton" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +selected = 0 +fit_to_longest_item = false +item_count = 3 +popup/item_0/text = "Add" +popup/item_1/text = "Erase" +popup/item_1/id = 1 +popup/item_2/text = "Remove From Recent" +popup/item_2/id = 2 + +[node name="AddRecentFromSel" type="Button" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +tooltip_text = "Add from selected cells" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2") +icon_name = "ListSelect" + +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/String" to="." method="_on_String_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Int" to="." method="_on_Int_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Float" to="." method="_on_Float_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Variant" to="." method="_on_Variant_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Object" to="." method="_on_Resource_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Remove" to="." method="_on_Remove_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Remove2" to="." method="_on_RemoveLast_pressed"] +[connection signal="pressed" from="HBoxContainer/Control2/HBoxContainer/HFlowContainer/AddRecentFromSel" to="." method="_on_AddRecentFromSel_pressed"] diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_base.gd b/addons/resources_spreadsheet_view/typed_editors/dock_base.gd new file mode 100644 index 0000000..79d4229 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_base.gd @@ -0,0 +1,50 @@ +@tool +class_name ResourceTablesDockEditor +extends Control + +const TablesPluginSettingsClass := preload("res://addons/resources_spreadsheet_view/settings_grid.gd") + +@export var path_property_name := NodePath("Header/Label") + +var sheet : Control +var selection : Array + +var _resize_target_height := 0.0 +var _resize_pressed := false + + +func _ready(): + var parent := get_parent() + while parent != null and !parent.has_method(&"display_folder"): + parent = parent.get_parent() + + sheet = parent + get_node(path_property_name).add_theme_font_override(&"normal", get_theme_font(&"bold", &"EditorFonts")) + + $"Header".gui_input.connect(_on_header_gui_input) + $"Header".mouse_filter = MOUSE_FILTER_STOP + $"Header".mouse_default_cursor_shape = CURSOR_VSIZE + +## Override to define when to show the dock and, if it can edit the value, how to handle it. +func try_edit_value(value, type : int, property_hint : String) -> bool: + return true + +## Override to define behaviour when stretching the header to change size. +func resize_drag(to_height : float): + return + + +func resize_set_hidden(state : bool): + get_child(1).visible = !state + + +func _on_header_gui_input(event : InputEvent): + if event is InputEventMouseMotion and _resize_pressed: + _resize_target_height -= event.relative.y + custom_minimum_size.y = clamp(_resize_target_height, 0.0, get_viewport().size.y * 0.75) + resize_drag(_resize_target_height) + resize_set_hidden(_resize_target_height <= $"Header".size.y) + + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: + _resize_pressed = event.pressed + _resize_target_height = custom_minimum_size.y diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_base.gd.uid b/addons/resources_spreadsheet_view/typed_editors/dock_base.gd.uid new file mode 100644 index 0000000..55b93ba --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_base.gd.uid @@ -0,0 +1 @@ +uid://df8ahp8bxhdrd diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_color.gd b/addons/resources_spreadsheet_view/typed_editors/dock_color.gd new file mode 100644 index 0000000..6529ceb --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_color.gd @@ -0,0 +1,139 @@ +@tool +extends ResourceTablesDockEditor + +@onready var _value_rect := $"EditColor/ColorProper/ColorRect" +@onready var _color_picker_panel := $"EditColor/VSeparator6/Panel" +@onready var _color_picker := $"EditColor/VSeparator6/Panel/MarginContainer/ColorPicker" +@onready var _custom_value_edit := $"EditColor/CustomX/Box/LineEdit" + +var _stored_value := Color.WHITE +var _resize_height_small := 0.0 +var _resize_expanded := true + + +func _ready(): + super._ready() + _connect_buttons($"EditColor/RGBGrid", 0, 0) + _connect_buttons($"EditColor/RGBGrid", 5, 1) + _connect_buttons($"EditColor/RGBGrid", 10, 2) + _connect_buttons($"EditColor/HSVGrid", 0, 3) + _connect_buttons($"EditColor/HSVGrid", 5, 4) + _connect_buttons($"EditColor/HSVGrid", 10, 5) + + _resize_height_small = get_child(1).get_minimum_size().y + + +func _connect_buttons(grid, start_index, property_bind): + grid.get_child(start_index + 0).pressed.connect(_increment_values_custom.bind(-1.0, property_bind)) + grid.get_child(start_index + 1).pressed.connect(_increment_values.bind(-10.0, property_bind)) + grid.get_child(start_index + 3).pressed.connect(_increment_values.bind(10.0, property_bind)) + grid.get_child(start_index + 4).pressed.connect(_increment_values_custom.bind(1.0, property_bind)) + + +func try_edit_value(value, type, property_hint) -> bool: + _color_picker_panel.top_level = false + if type != TYPE_COLOR: + return false + + _set_stored_value(value) + _color_picker_panel.visible = false + return true + + +func resize_drag(to_height : float): + var expanded := to_height > _resize_height_small + if _resize_expanded == expanded: + return + + _resize_expanded = expanded + $"EditColor/RGBGrid".visible = expanded + $"EditColor/ColorProper".visible = expanded + $"EditColor/HSVGrid".columns = 5 if expanded else 15 + $"EditColor/CustomX/Label".visible = expanded + + +func _set_stored_value(v): + _stored_value = v + _color_picker.color = v + _value_rect.color = v + + +func _increment_values(by : float, property : int): + var cell_values : Array = sheet.get_edited_cells_values() + match property: + 0: + _stored_value.r += by / 255.0 + for i in cell_values.size(): + cell_values[i].r += by / 255.0 + + 1: + _stored_value.g += by / 255.0 + for i in cell_values.size(): + cell_values[i].g += by / 255.0 + + 2: + _stored_value.b += by / 255.0 + for i in cell_values.size(): + cell_values[i].b += by / 255.0 + + 3: + # Hue has 360 degrees and loops + _stored_value.h += by / 360.0 + for i in cell_values.size(): + cell_values[i].h = fposmod(cell_values[i].h + by / 360.0, 1.0) + + 4: + _stored_value.s += by * 0.005 + for i in cell_values.size(): + cell_values[i].s += by * 0.005 + + 5: + _stored_value.v += by * 0.005 + for i in cell_values.size(): + cell_values[i].v += by * 0.005 + + _set_stored_value(_stored_value) + sheet.set_edited_cells_values(cell_values) + + +func _increment_values_custom(multiplier : float, property : int): + if property == 4 or property == 5: + # Numbered buttons increment by 5 for Sat and Value, so hue is x0.5 effect. Negate it here + multiplier *= 2.0 + + _increment_values(_custom_value_edit.text.to_float() * multiplier, property) + + +func _on_Button_pressed(): + _color_picker_panel.visible = !_color_picker_panel.visible + if _color_picker_panel.visible: + _color_picker_panel.top_level = true + _color_picker_panel.global_position = ( + sheet.global_position + + Vector2(0, sheet.size.y - _color_picker_panel.size.y) + + Vector2(16, -16) + ) + _color_picker_panel.global_position.y = clamp( + _color_picker_panel.global_position.y, + 0, + sheet.editor_plugin.get_editor_interface().get_base_control().size.y + ) + _color_picker.color = _stored_value + + elif _color_picker.color != _stored_value: + _set_stored_value(_color_picker.color) + update_cell_values() + + +func _on_ColorPicker_gui_input(event : InputEvent): + if event is InputEventMouseButton and !event.pressed: + _set_stored_value(_color_picker.color) + update_cell_values() + + +func update_cell_values(): + var values = sheet.get_edited_cells_values() + for i in values.size(): + values[i] = _stored_value + + sheet.set_edited_cells_values(values) diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_color.gd.uid b/addons/resources_spreadsheet_view/typed_editors/dock_color.gd.uid new file mode 100644 index 0000000..93dad6f --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_color.gd.uid @@ -0,0 +1 @@ +uid://b0r0qvpoir6bj diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_color.tscn b/addons/resources_spreadsheet_view/typed_editors/dock_color.tscn new file mode 100644 index 0000000..d7774e1 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_color.tscn @@ -0,0 +1,295 @@ +[gd_scene load_steps=2 format=3 uid="uid://b3a3bo6cfyh5t"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_editors/dock_color.gd" id="1"] + +[node name="EditColor" type="VBoxContainer"] +offset_bottom = 131.0 +grow_horizontal = 2 +mouse_filter = 0 +script = ExtResource("1") + +[node name="Header" type="HBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 9 + +[node name="HBoxContainer" type="HBoxContainer" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Header/HBoxContainer"] +layout_mode = 2 +text = "EDIT: Color" + +[node name="HSeparator" type="HSeparator" parent="Header/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="Label" type="Label" parent="Header"] +layout_mode = 2 +text = "PROPERTY NAME" + +[node name="HSeparator2" type="HSeparator" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="EditColor" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +alignment = 1 + +[node name="VSeparator7" type="Control" parent="EditColor"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="VSeparator3" type="Control" parent="EditColor"] +visible = false +layout_mode = 2 + +[node name="ButtonRowTemplate" type="Control" parent="EditColor"] +visible = false +layout_mode = 2 + +[node name="Button3" type="Button" parent="EditColor/ButtonRowTemplate"] +layout_mode = 0 +text = "-X" + +[node name="Button2" type="Button" parent="EditColor/ButtonRowTemplate"] +layout_mode = 0 +text = "-5" + +[node name="Label" type="Label" parent="EditColor/ButtonRowTemplate"] +layout_mode = 0 +text = "Red" + +[node name="Button5" type="Button" parent="EditColor/ButtonRowTemplate"] +layout_mode = 0 +text = "+5" + +[node name="Button6" type="Button" parent="EditColor/ButtonRowTemplate"] +layout_mode = 0 +text = "+X" + +[node name="RGBGrid" type="GridContainer" parent="EditColor"] +layout_mode = 2 +columns = 5 + +[node name="Button3" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(1, 0.780392, 0.780392, 1) +layout_mode = 2 +text = "-X" + +[node name="Button2" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(1, 0.780392, 0.780392, 1) +layout_mode = 2 +text = "-10" + +[node name="Label" type="Label" parent="EditColor/RGBGrid"] +layout_mode = 2 +text = "Red" +horizontal_alignment = 1 + +[node name="Button5" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(1, 0.780392, 0.780392, 1) +layout_mode = 2 +text = "+10" + +[node name="Button6" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(1, 0.780392, 0.780392, 1) +layout_mode = 2 +text = "+X" + +[node name="Button7" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.666667, 1, 0.745098, 1) +layout_mode = 2 +text = "-X" + +[node name="Button8" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.666667, 1, 0.745098, 1) +layout_mode = 2 +text = "-10" + +[node name="Label2" type="Label" parent="EditColor/RGBGrid"] +layout_mode = 2 +text = "Green" +horizontal_alignment = 1 + +[node name="Button11" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.666667, 1, 0.745098, 1) +layout_mode = 2 +text = "+10" + +[node name="Button12" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.666667, 1, 0.745098, 1) +layout_mode = 2 +text = "+X" + +[node name="Button13" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.772549, 0.792157, 1, 1) +layout_mode = 2 +text = "-X" + +[node name="Button14" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.772549, 0.792157, 1, 1) +layout_mode = 2 +text = "-10" + +[node name="Label3" type="Label" parent="EditColor/RGBGrid"] +layout_mode = 2 +text = "Blue" +horizontal_alignment = 1 + +[node name="Button17" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.772549, 0.792157, 1, 1) +layout_mode = 2 +text = "+10" + +[node name="Button18" type="Button" parent="EditColor/RGBGrid"] +modulate = Color(0.772549, 0.792157, 1, 1) +layout_mode = 2 +text = "+X" + +[node name="VSeparator" type="VSeparator" parent="EditColor"] +layout_mode = 2 + +[node name="ColorProper" type="VBoxContainer" parent="EditColor"] +layout_mode = 2 + +[node name="ColorRect" type="ColorRect" parent="EditColor/ColorProper"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="Button" type="Button" parent="EditColor/ColorProper"] +layout_mode = 2 +text = "Choose Color" + +[node name="VSeparator2" type="VSeparator" parent="EditColor"] +layout_mode = 2 + +[node name="HSVGrid" type="GridContainer" parent="EditColor"] +layout_mode = 2 +columns = 5 + +[node name="Button3" type="Button" parent="EditColor/HSVGrid"] +modulate = Color(1, 0.913725, 0.776471, 1) +layout_mode = 2 +text = "-X" + +[node name="Button2" type="Button" parent="EditColor/HSVGrid"] +modulate = Color(0.898039, 1, 0.698039, 1) +layout_mode = 2 +text = "-10" + +[node name="Label" type="Label" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "Hue" +horizontal_alignment = 1 + +[node name="Button5" type="Button" parent="EditColor/HSVGrid"] +modulate = Color(0.717647, 1, 0.980392, 1) +layout_mode = 2 +text = "+10" + +[node name="Button6" type="Button" parent="EditColor/HSVGrid"] +modulate = Color(0.74902, 0.729412, 1, 1) +layout_mode = 2 +text = "+X" + +[node name="Button7" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "-X" + +[node name="Button8" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "-5" + +[node name="Label2" type="Label" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "Sat" +horizontal_alignment = 1 + +[node name="Button11" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "+5" + +[node name="Button12" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "+X" + +[node name="Button13" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "-X" + +[node name="Button14" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "-5" + +[node name="Label3" type="Label" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "Value" +horizontal_alignment = 1 + +[node name="Button17" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "+5" + +[node name="Button18" type="Button" parent="EditColor/HSVGrid"] +layout_mode = 2 +text = "+X" + +[node name="VSeparator4" type="VSeparator" parent="EditColor"] +layout_mode = 2 + +[node name="CustomX" type="VBoxContainer" parent="EditColor"] +layout_mode = 2 + +[node name="Label" type="Label" parent="EditColor/CustomX"] +layout_mode = 2 +size_flags_vertical = 6 +text = "Custom Value" +horizontal_alignment = 1 + +[node name="Box" type="HBoxContainer" parent="EditColor/CustomX"] +layout_mode = 2 + +[node name="Label2" type="Label" parent="EditColor/CustomX/Box"] +layout_mode = 2 +size_flags_vertical = 6 +text = "X =" + +[node name="LineEdit" type="LineEdit" parent="EditColor/CustomX/Box"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "20" + +[node name="VSeparator6" type="Control" parent="EditColor"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Panel" type="PanelContainer" parent="EditColor/VSeparator6"] +visible = false +layout_mode = 1 +anchors_preset = 2 +anchor_top = 1.0 +anchor_bottom = 1.0 +grow_vertical = 0 + +[node name="Panel2" type="Panel" parent="EditColor/VSeparator6/Panel"] +self_modulate = Color(1.5, 1.5, 1.5, 1) +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="EditColor/VSeparator6/Panel"] +layout_mode = 2 + +[node name="ColorPicker" type="ColorPicker" parent="EditColor/VSeparator6/Panel/MarginContainer"] +layout_mode = 2 + +[node name="Button" type="Button" parent="EditColor/VSeparator6/Panel/MarginContainer/ColorPicker"] +layout_mode = 2 +text = "OK" + +[connection signal="pressed" from="EditColor/ColorProper/Button" to="." method="_on_Button_pressed"] +[connection signal="gui_input" from="EditColor/VSeparator6/Panel/MarginContainer/ColorPicker" to="." method="_on_ColorPicker_gui_input"] +[connection signal="pressed" from="EditColor/VSeparator6/Panel/MarginContainer/ColorPicker/Button" to="." method="_on_Button_pressed"] diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_dict.gd b/addons/resources_spreadsheet_view/typed_editors/dock_dict.gd new file mode 100644 index 0000000..f64eff4 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_dict.gd @@ -0,0 +1,201 @@ +@tool +extends "res://addons/resources_spreadsheet_view/typed_editors/dock_array.gd" + +enum { + KEY_TYPE_STRINGNAME = 0, + KEY_TYPE_INT, + KEY_TYPE_FLOAT, + KEY_TYPE_OBJECT, + KEY_TYPE_VARIANT, +} + +@onready var key_input := $"HBoxContainer/HBoxContainer/Control/VBoxContainer/KeyEdit/KeyEdit" +@onready var key_type := $"HBoxContainer/HBoxContainer/Control/VBoxContainer/KeyEdit/KeyType" + +var _key_type_selected := 0 + + +func try_edit_value(value, type, property_hint) -> bool: + if type != TYPE_DICTIONARY and type != TYPE_OBJECT: + return false + + if value is Texture2D: + # For textures, prefer the specialized dock. + return false + + key_type.visible = type != TYPE_OBJECT + + _stored_type = type + if type == TYPE_DICTIONARY: + _stored_value = value.duplicate() + + contents_label.text = var_to_str_no_sort(value) + + return true + + +func _add_value(value): + var key = _get_key_from_box() + _stored_value[key] = value + + var values : Array = sheet.get_edited_cells_values() + var cur_value + var dupe_value : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_value and (_stored_type == TYPE_DICTIONARY or cur_value.resource_path.rfind("::") != -1): + cur_value = cur_value.duplicate() + + cur_value[key] = value + values[i] = cur_value + + sheet.set_edited_cells_values(values) + super._add_recent(key) + + +func _add_values(added_values : Array): + for x in added_values: + _add_value(x) + + +func _remove_value(_value): + var key = _get_key_from_box() + _stored_value.erase(key) + + var values : Array = sheet.get_edited_cells_values() + var cur_value + var dupe_value : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_value and (_stored_type == TYPE_DICTIONARY or cur_value.resource_path.rfind("::") != -1): + cur_value = cur_value.duplicate() + + cur_value.erase(key) + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _get_key_from_box(): + if _stored_type == TYPE_OBJECT: + return StringName(key_input.text) + + return _to_key(key_input.text, _key_type_selected) + + +func _to_key(from : String, key_type : int): + match key_type: + KEY_TYPE_STRINGNAME: + return StringName(from) + + KEY_TYPE_INT: + return from.to_int() + + KEY_TYPE_FLOAT: + return from.to_float() + + KEY_TYPE_OBJECT: + return load(from) + + KEY_TYPE_VARIANT: + return str_to_var(from) + + +func _on_Replace_pressed(): + var old_key = _to_key(key_input.text, _key_type_selected) + var new_key = _to_key(value_input.text, _key_type_selected) + _stored_value[new_key] = _stored_value[old_key] + + var values : Array = sheet.get_edited_cells_values() + var cur_value + var dupe_value : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_value and (_stored_type == TYPE_DICTIONARY or cur_value.resource_path.rfind("::") != -1): + cur_value = cur_value.duplicate() + + cur_value[new_key] = cur_value[old_key] + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _add_recent(_value): + pass + + +func _on_recent_clicked(button, value): + var val : int = recent_container.get_child(1).selected + key_input.text = str(value) + if val == 0: + # Do nothing! What if the value for the key doesn't match? + pass + + if val == 1: + _remove_value(value) + + if val == 2: + button.queue_free() + + +func _on_key_type_selected(index : int): + _key_type_selected = index + + +func _on_AddRecentFromSel_pressed(): + for x in sheet.get_edited_cells_values(): + if _stored_type == TYPE_OBJECT: + for y in x.get_property_list(): + if y[&"usage"] & PROPERTY_USAGE_EDITOR != 0: + super._add_recent(y[&"name"]) + + else: + for y in x: + super._add_recent(y) + + +func _on_contents_edit_text_changed(): + var value = str_to_var(contents_label.text) + if !value is Dictionary: + return + + var values : Array = sheet.get_edited_cells_values() + for i in values.size(): + values[i] = value.duplicate() + + _stored_value = value + sheet.set_edited_cells_values(values) + + +func var_to_str_no_sort(value, indent = " ", cur_indent = ""): + var lines : Array[String] = [] + + if value is Array: + cur_indent += indent + lines.resize(value.size()) + for i in lines.size(): + if value[i] is Array or value[i] is Dictionary: + lines[i] = "%s%s" % [cur_indent, var_to_str_no_sort(value[i])] + + else: + lines[i] = "%s%s" % [cur_indent, var_to_str(value[i])] + + cur_indent = cur_indent.substr(0, cur_indent.length() - indent.length()) + return "[\n" + ",\n".join(lines) + "\n]" + + if value is Dictionary: + var keys : Array = value.keys() + var values : Array = value.values() + cur_indent += indent + lines.resize(keys.size()) + for i in lines.size(): + if values[i] is Array or values[i] is Dictionary: + lines[i] = "%s%s : %s" % [cur_indent, var_to_str(keys[i]), var_to_str_no_sort(values[i])] + + else: + lines[i] = "%s%s : %s" % [cur_indent, var_to_str(keys[i]), var_to_str(values[i])] + + cur_indent = cur_indent.substr(0, cur_indent.length() - indent.length()) + return "{\n" + ",\n".join(lines) + "\n}" + + return ",\n".join(lines) diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_dict.gd.uid b/addons/resources_spreadsheet_view/typed_editors/dock_dict.gd.uid new file mode 100644 index 0000000..5ee58ff --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_dict.gd.uid @@ -0,0 +1 @@ +uid://b6oaeekpc877t diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_dict.tscn b/addons/resources_spreadsheet_view/typed_editors/dock_dict.tscn new file mode 100644 index 0000000..44981ce --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_dict.tscn @@ -0,0 +1,226 @@ +[gd_scene load_steps=5 format=3 uid="uid://p6x03dbvhnqw"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_editors/dock_dict.gd" id="1_2yivi"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="2_yck0k"] + +[sub_resource type="Image" id="Image_bq2wd"] +data = { +"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 93, 93, 55, 255, 97, 97, 58, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 98, 98, 47, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 94, 94, 46, 255, 93, 93, 236, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id="ImageTexture_3oshq"] +image = SubResource("Image_bq2wd") + +[node name="EditArray" type="VBoxContainer"] +anchors_preset = 10 +anchor_right = 1.0 +grow_horizontal = 2 +mouse_filter = 0 +script = ExtResource("1_2yivi") + +[node name="Header" type="HBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 9 + +[node name="HBoxContainer" type="HBoxContainer" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Header/HBoxContainer"] +layout_mode = 2 +text = "EDIT: Dict/Object" + +[node name="HSeparator" type="HSeparator" parent="Header/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="Label" type="Label" parent="Header"] +layout_mode = 2 +text = "PROPERTY NAME" + +[node name="HSeparator2" type="HSeparator" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="HBoxContainer" type="HSplitContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +split_offset = 520 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer"] +layout_mode = 2 +alignment = 2 + +[node name="Panel" type="MarginContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="TextEdit" parent="HBoxContainer/HBoxContainer/Panel"] +layout_mode = 2 +size_flags_vertical = 5 +text = "[]" + +[node name="VSeparator2" type="VSeparator" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="Control" type="HBoxContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer/HBoxContainer/Control"] +layout_mode = 2 + +[node name="KeyEdit" type="HBoxContainer" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 + +[node name="KeyEdit" type="LineEdit" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/KeyEdit"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "Input key to add/change/erase..." +clear_button_enabled = true + +[node name="KeyType" type="OptionButton" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/KeyEdit"] +layout_mode = 2 +selected = 0 +fit_to_longest_item = false +item_count = 5 +popup/item_0/text = "Stringname" +popup/item_1/text = "Int" +popup/item_1/id = 1 +popup/item_2/text = "Float" +popup/item_2/id = 2 +popup/item_3/text = "Resource path" +popup/item_3/id = 4 +popup/item_4/text = "Guess type" +popup/item_4/id = 3 + +[node name="LineEdit" type="LineEdit" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "Input value..." +clear_button_enabled = true + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Set value with type:" + +[node name="String" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Set to string" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "String" + +[node name="Int" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Set to integer" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "int" + +[node name="Float" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Set to float" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "float" + +[node name="Variant" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Guess type and set" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "Variant" + +[node name="Object" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Set to resource (by path if string)" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "Object" + +[node name="Label2" type="Label" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Key:" + +[node name="Remove" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Erase keys in Key textbox" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "Remove" + +[node name="Replace" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Copy Key's value to new key +Example: +- key box = \"thing\" +- value box = \"thing two\" +- old dict = {\"thing\" : 12} +- resulting dict = {\"thing\" : 12, \"thing two\" : 12}" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "Override" + +[node name="VSeparator" type="VSeparator" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="Control2" type="ScrollContainer" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +follow_focus = true +horizontal_scroll_mode = 0 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/Control2"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +alignment = 2 + +[node name="VSeparator2" type="VSeparator" parent="HBoxContainer/Control2/HBoxContainer"] +layout_mode = 2 + +[node name="HFlowContainer" type="HFlowContainer" parent="HBoxContainer/Control2/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +text = "Recent:" + +[node name="OptionButton" type="OptionButton" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +selected = 0 +fit_to_longest_item = false +item_count = 3 +popup/item_0/text = "Add" +popup/item_1/text = "Erase" +popup/item_1/id = 1 +popup/item_2/text = "Remove From Recent" +popup/item_2/id = 2 + +[node name="AddRecentFromSel" type="Button" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +tooltip_text = "Add from selected cells" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_yck0k") +icon_name = "ListSelect" + +[connection signal="item_selected" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/KeyEdit/KeyType" to="." method="_on_key_type_selected"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/String" to="." method="_on_String_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Int" to="." method="_on_Int_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Float" to="." method="_on_Float_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Variant" to="." method="_on_Variant_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Object" to="." method="_on_Resource_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Remove" to="." method="_on_Remove_pressed"] +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/HBoxContainer/Replace" to="." method="_on_Replace_pressed"] +[connection signal="pressed" from="HBoxContainer/Control2/HBoxContainer/HFlowContainer/AddRecentFromSel" to="." method="_on_AddRecentFromSel_pressed"] diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd b/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd new file mode 100644 index 0000000..1398a24 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd @@ -0,0 +1,137 @@ +@tool +extends ResourceTablesDockEditor + +@onready var options_container := $"HBoxContainer/Control2/HBoxContainer/HFlowContainer" +@onready var contents_label := $"HBoxContainer/HBoxContainer/Panel/Label" + +@onready var _init_nodes_in_options_container := options_container.get_child_count() + +var _stored_value +var _last_column := -1 + + +func _ready(): + super() + contents_label.text_changed.connect(_on_contents_edit_text_changed) + + +func try_edit_value(value, type, property_hint) -> bool: + if !sheet.column_hint_strings[sheet.get_selected_column()][0].begins_with("2/2:"): + return false + + _stored_value = value.duplicate() # Generic arrays are passed by reference + if _last_column != sheet.get_selected_column(): + _last_column = sheet.get_selected_column() + for x in options_container.get_children(): + x.visible = x.get_index() < _init_nodes_in_options_container + + for i in sheet.column_hint_strings[sheet.get_selected_column()].size(): + _create_option_button(i) + + contents_label.text = str(value) + return true + + +func _create_option_button(index : int): + var value = sheet.column_hint_strings[sheet.get_selected_column()][index] + if index == 0: + # Enum array hints have "2/3:" before list. + value = value.substr(value.find(":") + 1) + + var node + if index >= options_container.get_child_count() - _init_nodes_in_options_container: + node = Button.new() + options_container.add_child(node) + var colon_found : int = value.rfind(":") + if colon_found == -1: + node.pressed.connect(_on_option_clicked.bind(index)) + + else: + node.pressed.connect(_on_option_clicked.bind(value.substr(colon_found + 1).to_int())) + + else: + node = options_container.get_child(index + _init_nodes_in_options_container) + node.visible = true + + node.text = str(value) + node.self_modulate = Color(value.hash()) + Color(0.25, 0.25, 0.25, 1.0) + return node + + +func _add_value(option_value : int): + _stored_value.append(option_value) + var values : Array = sheet.get_edited_cells_values() + var cur_value + var dupe_array : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_array: + cur_value = cur_value.duplicate() + + cur_value.append(option_value) + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _remove_value(option_value : int): + _stored_value.append(option_value) + var values : Array = sheet.get_edited_cells_values() + var cur_value + var dupe_array : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_array: + cur_value = cur_value.duplicate() + + if cur_value.has(option_value): + cur_value.remove_at(cur_value.find(option_value)) + + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _on_option_clicked(value : int): + var val = options_container.get_child(1).selected + if val == 0: + _add_value(value) + + if val == 1: + _remove_value(value) + + +func _on_Remove_pressed(): + _stored_value.remove_at(_stored_value.size() - 1) + var values = sheet.get_edited_cells_values() + var cur_value + var dupe_array : bool = ProjectSettings.get_setting(TablesPluginSettingsClass.PREFIX + "dupe_arrays") + for i in values.size(): + cur_value = values[i] + if dupe_array: + cur_value = cur_value.duplicate() + + cur_value.remove_at(cur_value.size() - 1) + values[i] = cur_value + + sheet.set_edited_cells_values(values) + + +func _on_contents_edit_text_changed(): + var value = str_to_var(contents_label.text) + if !value is Array: + return + + for x in value: + if !x is int: + return + + var values = sheet.get_edited_cells_values() + for i in values.size(): + values[i] = values[i].duplicate() + values[i].resize(value.size()) + for j in value.size(): + values[i][j] = value[j] + + _stored_value = value + sheet.set_edited_cells_values(values) diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd.uid b/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd.uid new file mode 100644 index 0000000..2202458 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd.uid @@ -0,0 +1 @@ +uid://dyesxoow0jp28 diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.tscn b/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.tscn new file mode 100644 index 0000000..c1540d5 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_enum_array.tscn @@ -0,0 +1,117 @@ +[gd_scene load_steps=5 format=3 uid="uid://ddqak780cwwfj"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_editors/dock_enum_array.gd" id="1_n3flg"] +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/editor_icon_button.gd" id="2_mda1e"] + +[sub_resource type="Image" id="Image_5ktp6"] +data = { +"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 93, 93, 55, 255, 97, 97, 58, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 98, 98, 47, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 94, 94, 46, 255, 93, 93, 236, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id="ImageTexture_3oshq"] +image = SubResource("Image_5ktp6") + +[node name="EditEnumArray" type="VBoxContainer"] +anchors_preset = 10 +anchor_right = 1.0 +mouse_filter = 0 +script = ExtResource("1_n3flg") + +[node name="Header" type="HBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 9 + +[node name="HBoxContainer" type="HBoxContainer" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Header/HBoxContainer"] +layout_mode = 2 +text = "EDIT: Enum Array" + +[node name="HSeparator" type="HSeparator" parent="Header/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="Label" type="Label" parent="Header"] +layout_mode = 2 +text = "PROPERTY NAME" + +[node name="HSeparator2" type="HSeparator" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="HBoxContainer" type="HSplitContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +split_offset = 250 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer"] +layout_mode = 2 +alignment = 2 + +[node name="Panel" type="MarginContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="TextEdit" parent="HBoxContainer/HBoxContainer/Panel"] +layout_mode = 2 +size_flags_vertical = 5 +text = "[]" + +[node name="VSeparator2" type="VSeparator" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="Control" type="MarginContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer/HBoxContainer/Control"] +layout_mode = 2 + +[node name="Remove" type="Button" parent="HBoxContainer/HBoxContainer/Control/VBoxContainer"] +layout_mode = 2 +text = "Remove Last Value" +icon = SubResource("ImageTexture_3oshq") +script = ExtResource("2_mda1e") +icon_name = "Remove" + +[node name="VSeparator" type="VSeparator" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="Control2" type="MarginContainer" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/Control2"] +layout_mode = 2 +alignment = 2 + +[node name="VSeparator2" type="VSeparator" parent="HBoxContainer/Control2/HBoxContainer"] +layout_mode = 2 + +[node name="HFlowContainer" type="HFlowContainer" parent="HBoxContainer/Control2/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +text = "Options:" + +[node name="OptionButton" type="OptionButton" parent="HBoxContainer/Control2/HBoxContainer/HFlowContainer"] +layout_mode = 2 +item_count = 2 +selected = 0 +fit_to_longest_item = false +popup/item_0/text = "Add" +popup/item_0/id = 0 +popup/item_1/text = "Erase" +popup/item_1/id = 1 + +[connection signal="pressed" from="HBoxContainer/HBoxContainer/Control/VBoxContainer/Remove" to="." method="_on_Remove_pressed"] diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_number.gd b/addons/resources_spreadsheet_view/typed_editors/dock_number.gd new file mode 100644 index 0000000..591f7ff --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_number.gd @@ -0,0 +1,188 @@ +@tool +extends ResourceTablesDockEditor + +@onready var _value_label := $"HBoxContainer/HBoxContainer/NumberPanel/Label" +@onready var _button_grid := $"HBoxContainer/HBoxContainer/GridContainer" +@onready var _button_grid_small := $"HBoxContainer/HBoxContainer/GridContainerSmall" +@onready var _sequence_gen_inputs := $"HBoxContainer/CustomX2/HBoxContainer" +@onready var _custom_value_edit := $"HBoxContainer/CustomX/Box/LineEdit" + +var _stored_value = 0 +var _stored_value_is_int := false + +var _mouse_drag_increment := 0.0 +var _mouse_down := false + +var _resize_height_small := 0.0 +var _resize_expanded := true + + +func _ready(): + super._ready() + _button_grid.get_child(0).pressed.connect(_increment_values.bind(+0.1)) + _button_grid.get_child(1).pressed.connect(_increment_values.bind(+1)) + _button_grid.get_child(2).pressed.connect(_increment_values.bind(+10)) + _button_grid.get_child(3).pressed.connect(_increment_values.bind(+100)) + _button_grid.get_child(4).pressed.connect(_increment_values_custom.bind(true, false)) + _button_grid.get_child(5).pressed.connect(_increment_values_custom.bind(true, true)) + + _button_grid.get_child(6).pressed.connect(_increment_values.bind(-0.1)) + _button_grid.get_child(7).pressed.connect(_increment_values.bind(-1)) + _button_grid.get_child(8).pressed.connect(_increment_values.bind(-10)) + _button_grid.get_child(9).pressed.connect(_increment_values.bind(-100)) + _button_grid.get_child(10).pressed.connect(_increment_values_custom.bind(false, false)) + _button_grid.get_child(11).pressed.connect(_increment_values_custom.bind(false, true)) + + _button_grid_small.get_child(1).pressed.connect(_increment_values_custom.bind(false, true)) + _button_grid_small.get_child(2).pressed.connect(_increment_values_custom.bind(false, false)) + _button_grid_small.get_child(3).pressed.connect(_increment_values.bind(-1)) + _button_grid_small.get_child(4).pressed.connect(_increment_values.bind(+1)) + _button_grid_small.get_child(5).pressed.connect(_increment_values_custom.bind(true, false)) + _button_grid_small.get_child(6).pressed.connect(_increment_values_custom.bind(true, true)) + + _resize_height_small = get_child(1).get_minimum_size().y + + +func try_edit_value(value, type, property_hint) -> bool: + if type != TYPE_FLOAT and type != TYPE_INT: + return false + + _stored_value = value + _value_label.text = str(value) + + _stored_value_is_int = type != TYPE_FLOAT + _button_grid.columns = 5 if _stored_value_is_int else 6 + _button_grid.get_child(0).visible = !_stored_value_is_int + _button_grid.get_child(6).visible = !_stored_value_is_int + + return true + + +func resize_drag(to_height : float): + var expanded : bool = to_height >= _resize_height_small + if _resize_expanded == expanded: + return + + _resize_expanded = expanded + _button_grid.visible = expanded + _button_grid_small.visible = !expanded + $"HBoxContainer/CustomX2/HBoxContainer/Label2".visible = !expanded + $"HBoxContainer/CustomX2/HBoxContainer3".visible = expanded + $"HBoxContainer/HBoxContainer/NumberPanel".visible = expanded + $"HBoxContainer/CustomX2/HBoxContainer2".visible = expanded + $"HBoxContainer/CustomX2/HBoxContainer/Box".visible = !expanded + $"HBoxContainer/CustomX/Label".visible = expanded + + +func _increment_values(by : float): + var cell_values : Array = sheet.get_edited_cells_values() + if _stored_value_is_int: + _stored_value += int(by) + for i in cell_values.size(): + cell_values[i] += int(by) + + else: + _stored_value += by + for i in cell_values.size(): + cell_values[i] += by + + sheet.set_edited_cells_values(cell_values) + _value_label.text = str(_stored_value) + + +func _increment_values_custom(positive : bool, multiplier : bool): + var value := float(_custom_value_edit.text) + if !multiplier: + _increment_values(value if positive else -value) + + else: + if !positive: value = 1 / value + var cell_values : Array = sheet.get_edited_cells_values() + _stored_value *= value + for i in cell_values.size(): + cell_values[i] *= value + if _stored_value_is_int: + cell_values[i] = int(cell_values[i]) + + sheet.set_edited_cells_values(cell_values) + _value_label.text = str(_stored_value) + + +func _on_NumberPanel_gui_input(event): + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: + if event.pressed: + Input.mouse_mode = Input.MOUSE_MODE_CAPTURED + _mouse_drag_increment = 0.0 + _mouse_down = true + + else: + Input.mouse_mode = Input.MOUSE_MODE_VISIBLE + if _mouse_down: + Input.warp_mouse(_value_label.global_position + _value_label.size * 0.5) + + _increment_values(_mouse_drag_increment) + _mouse_down = false + + if _mouse_down and event is InputEventMouseMotion: + if _stored_value_is_int: + _mouse_drag_increment += event.relative.x * 0.25 + _value_label.text = str(_stored_value + int(_mouse_drag_increment)) + + else: + _mouse_drag_increment += event.relative.x * 0.01 + _value_label.text = str(_stored_value + _mouse_drag_increment) + + +func _on_SequenceFill_pressed(add : bool = false): + sheet.set_edited_cells_values(_fill_sequence(sheet.get_edited_cells_values(), add)) + + +func _fill_sequence(arr : Array, add : bool = false) -> Array: + if !_sequence_gen_inputs.get_node("Start").text.is_valid_float(): + return arr + + var start := float(_sequence_gen_inputs.get_child(0).text) + var end = null + var step = null + + if _sequence_gen_inputs.get_node("Step").text.is_valid_float(): + step = float(_sequence_gen_inputs.get_node("Step").text) + + if _sequence_gen_inputs.get_node("End").text.is_valid_float(): + end = float(_sequence_gen_inputs.get_node("End").text) + + if end == null: + end = INF if step == null or step >= 0 else -INF + + var end_is_higher = end > start + if step == null: + if end == null or end == INF or end == -INF: + step = 0.0 + + else: + step = (end - start) / arr.size() + + if _stored_value_is_int: + if start != null: + start = int(start) + + if step != null: + step = int(step) + + if end != INF and end != -INF: + end = int(end) + + + var cur = start + if !add: + for i in arr.size(): + arr[i] = 0 + + # The range() global function can also be used, but does not work with floats. + for i in arr.size(): + arr[i] = arr[i] + cur + cur += step + if (end_is_higher and cur >= end) or (!end_is_higher and cur <= end): + cur += (start - end) + + return arr diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_number.gd.uid b/addons/resources_spreadsheet_view/typed_editors/dock_number.gd.uid new file mode 100644 index 0000000..9ca86a3 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_number.gd.uid @@ -0,0 +1 @@ +uid://3orfotlxpjrk diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_number.tscn b/addons/resources_spreadsheet_view/typed_editors/dock_number.tscn new file mode 100644 index 0000000..86eea13 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_number.tscn @@ -0,0 +1,265 @@ +[gd_scene load_steps=2 format=3 uid="uid://gtbf7b0wptv"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_editors/dock_number.gd" id="1"] + +[node name="EditNumber" type="VBoxContainer"] +offset_right = 1141.0 +offset_bottom = 126.0 +mouse_filter = 0 +script = ExtResource("1") + +[node name="Header" type="HBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 9 + +[node name="HBoxContainer" type="HBoxContainer" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Header/HBoxContainer"] +layout_mode = 2 +text = "EDIT: Number" + +[node name="HSeparator" type="HSeparator" parent="Header/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="Label" type="Label" parent="Header"] +layout_mode = 2 +text = "PROPERTY NAME" + +[node name="HSeparator2" type="HSeparator" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +alignment = 1 + +[node name="CustomX2" type="VBoxContainer" parent="HBoxContainer"] +layout_mode = 2 + +[node name="HBoxContainer3" type="HBoxContainer" parent="HBoxContainer/CustomX2"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="Label" type="Label" parent="HBoxContainer/CustomX2/HBoxContainer3"] +layout_mode = 2 +size_flags_vertical = 6 +text = "Fill with Sequence" + +[node name="Label2" type="Label" parent="HBoxContainer/CustomX2/HBoxContainer3"] +layout_mode = 2 +size_flags_vertical = 6 +tooltip_text = "Fill selected cells with a number sequence. Order is the same as the cells were selected. +- You must specify Start. +- If all values specified, selected cells will have a repeating sequence +of numbers from Start to End, with increment of Step, not including End. +- If both End AND Step are empty, cells are filled with Start. +- If End is omitted, selected cells will have values from Start to (Step x CellCount). +- If Step is omitted, selected cells will have values from Start to End inclusive, +step based on cell count." +mouse_filter = 0 +mouse_default_cursor_shape = 16 +text = "(?)" + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/CustomX2"] +layout_mode = 2 + +[node name="Label2" type="Label" parent="HBoxContainer/CustomX2/HBoxContainer"] +visible = false +layout_mode = 2 +text = "Sequence" + +[node name="Start" type="LineEdit" parent="HBoxContainer/CustomX2/HBoxContainer"] +layout_mode = 2 +tooltip_text = "Start (must not be blank)" +placeholder_text = "Start *" + +[node name="End" type="LineEdit" parent="HBoxContainer/CustomX2/HBoxContainer"] +layout_mode = 2 +tooltip_text = "End" +placeholder_text = "End" + +[node name="Step" type="LineEdit" parent="HBoxContainer/CustomX2/HBoxContainer"] +layout_mode = 2 +tooltip_text = "End" +placeholder_text = "Step" + +[node name="Box" type="HBoxContainer" parent="HBoxContainer/CustomX2/HBoxContainer"] +visible = false +layout_mode = 2 + +[node name="VSeparator" type="VSeparator" parent="HBoxContainer/CustomX2/HBoxContainer/Box"] +layout_mode = 2 + +[node name="SequenceFill3" type="Button" parent="HBoxContainer/CustomX2/HBoxContainer/Box"] +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "Set" +text = "=" + +[node name="SequenceFill4" type="Button" parent="HBoxContainer/CustomX2/HBoxContainer/Box"] +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "Add to each value" +text = "+" + +[node name="HBoxContainer2" type="HBoxContainer" parent="HBoxContainer/CustomX2"] +layout_mode = 2 + +[node name="SequenceFill" type="Button" parent="HBoxContainer/CustomX2/HBoxContainer2"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Set" + +[node name="SequenceFill2" type="Button" parent="HBoxContainer/CustomX2/HBoxContainer2"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Add" + +[node name="VSeparator2" type="VSeparator" parent="HBoxContainer"] +layout_mode = 2 + +[node name="HBoxContainer" type="VBoxContainer" parent="HBoxContainer"] +layout_mode = 2 +alignment = 1 + +[node name="NumberPanel" type="MarginContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +mouse_default_cursor_shape = 10 + +[node name="Panel" type="Panel" parent="HBoxContainer/HBoxContainer/NumberPanel"] +layout_mode = 2 +mouse_filter = 2 + +[node name="Label" type="Label" parent="HBoxContainer/HBoxContainer/NumberPanel"] +layout_mode = 2 +text = "1" +clip_text = true + +[node name="GridContainer" type="GridContainer" parent="HBoxContainer/HBoxContainer"] +layout_mode = 2 +columns = 6 + +[node name="Button15" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "+0.1" + +[node name="Button12" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "+1" + +[node name="Button8" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "+10" + +[node name="Button13" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "+100" + +[node name="Button9" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "+X" + +[node name="Button16" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "*X" + +[node name="Button14" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "-0.1" + +[node name="Button11" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "-1" + +[node name="Button7" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "-10" + +[node name="Button10" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "-100" + +[node name="Button4" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "-X" + +[node name="Button5" type="Button" parent="HBoxContainer/HBoxContainer/GridContainer"] +layout_mode = 2 +text = "/X" + +[node name="GridContainerSmall" type="HBoxContainer" parent="HBoxContainer/HBoxContainer"] +visible = false +layout_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer/HBoxContainer/GridContainerSmall"] +layout_mode = 2 +text = "Value" + +[node name="Button1" type="Button" parent="HBoxContainer/HBoxContainer/GridContainerSmall"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "/X" + +[node name="Button2" type="Button" parent="HBoxContainer/HBoxContainer/GridContainerSmall"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "-X" + +[node name="Button3" type="Button" parent="HBoxContainer/HBoxContainer/GridContainerSmall"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "-1" + +[node name="Button4" type="Button" parent="HBoxContainer/HBoxContainer/GridContainerSmall"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "+1" + +[node name="Button5" type="Button" parent="HBoxContainer/HBoxContainer/GridContainerSmall"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "+X" + +[node name="Button6" type="Button" parent="HBoxContainer/HBoxContainer/GridContainerSmall"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "*X" + +[node name="VSeparator" type="VSeparator" parent="HBoxContainer"] +layout_mode = 2 + +[node name="CustomX" type="VBoxContainer" parent="HBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer/CustomX"] +layout_mode = 2 +size_flags_vertical = 6 +text = "Custom Value" +horizontal_alignment = 1 + +[node name="Box" type="HBoxContainer" parent="HBoxContainer/CustomX"] +layout_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer/CustomX/Box"] +layout_mode = 2 +text = "X =" + +[node name="LineEdit" type="LineEdit" parent="HBoxContainer/CustomX/Box"] +custom_minimum_size = Vector2(96, 0) +layout_mode = 2 +size_flags_horizontal = 3 +text = "1000" + +[connection signal="pressed" from="HBoxContainer/CustomX2/HBoxContainer/Box/SequenceFill3" to="." method="_on_SequenceFill_pressed"] +[connection signal="pressed" from="HBoxContainer/CustomX2/HBoxContainer/Box/SequenceFill4" to="." method="_on_SequenceFill_pressed"] +[connection signal="pressed" from="HBoxContainer/CustomX2/HBoxContainer2/SequenceFill" to="." method="_on_SequenceFill_pressed"] +[connection signal="pressed" from="HBoxContainer/CustomX2/HBoxContainer2/SequenceFill2" to="." method="_on_SequenceFill_pressed" binds= [true]] +[connection signal="gui_input" from="HBoxContainer/HBoxContainer/NumberPanel" to="." method="_on_NumberPanel_gui_input"] diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_texture.gd b/addons/resources_spreadsheet_view/typed_editors/dock_texture.gd new file mode 100644 index 0000000..c163bbb --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_texture.gd @@ -0,0 +1,39 @@ +@tool +extends ResourceTablesDockEditor + +var _stored_value : Texture2D + + +func try_edit_value(value, type, _property_hint) -> bool: + if type != TYPE_OBJECT or !value is Texture: + return false + + _stored_value = value + $"HBoxContainer/TextureRect".texture = value + return true + + +func _on_Button_pressed(): + var h_count : int = $"HBoxContainer/VBoxContainer/HBoxContainer/LineEdit".text.to_int() + var v_count : int = $"HBoxContainer/VBoxContainer/HBoxContainer/LineEdit2".text.to_int() + # No, Scene Unique Names can not be used in-editor (last time i checked) + + var folder_name := _stored_value.resource_path.get_basename() + DirAccess.make_dir_recursive_absolute(folder_name) + + var tex_size := _stored_value.get_size() + var tile_size := Vector2(tex_size.x / h_count, tex_size.y / v_count) + var tile_array := [] + for j in v_count: + for i in h_count: + var tile := AtlasTexture.new() + tile.region = Rect2(tile_size * Vector2(i, j), tile_size) + tile.atlas = _stored_value + tile_array.append(tile) + tile.take_over_path(folder_name + "/" + folder_name.get_file() + "_" + str(j * h_count + i + 1) + ".tres") + ResourceSaver.save(tile) + + tile_array.resize(sheet.get_edited_cells_values().size()) + sheet.set_edited_cells_values(tile_array) + sheet.editor_plugin.get_editor_interface().get_resource_filesystem().scan() + diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_texture.gd.uid b/addons/resources_spreadsheet_view/typed_editors/dock_texture.gd.uid new file mode 100644 index 0000000..ff6e487 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_texture.gd.uid @@ -0,0 +1 @@ +uid://ngdi4j3lvvh7 diff --git a/addons/resources_spreadsheet_view/typed_editors/dock_texture.tscn b/addons/resources_spreadsheet_view/typed_editors/dock_texture.tscn new file mode 100644 index 0000000..fc2f411 --- /dev/null +++ b/addons/resources_spreadsheet_view/typed_editors/dock_texture.tscn @@ -0,0 +1,101 @@ +[gd_scene load_steps=3 format=3 uid="uid://rww3gpl052bn"] + +[ext_resource type="Script" path="res://addons/resources_spreadsheet_view/typed_editors/dock_texture.gd" id="1"] + +[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_h3mns"] + +[node name="EditTexture" type="VBoxContainer"] +anchors_preset = -1 +anchor_right = 1.0 +anchor_bottom = 0.25463 +offset_bottom = 126.0 +grow_horizontal = 2 +mouse_filter = 0 +script = ExtResource("1") +metadata/_edit_use_anchors_ = true + +[node name="Header" type="HBoxContainer" parent="."] +layout_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 9 + +[node name="HBoxContainer" type="HBoxContainer" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Header/HBoxContainer"] +layout_mode = 2 +text = "EDIT: Texture" + +[node name="HSeparator" type="HSeparator" parent="Header/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="Label" type="Label" parent="Header"] +layout_mode = 2 +text = "PROPERTY NAME" + +[node name="HSeparator2" type="HSeparator" parent="Header"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +alignment = 1 + +[node name="Control2" type="Control" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[node name="TextureRect" type="TextureRect" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +texture = SubResource("PlaceholderTexture2D_h3mns") +expand_mode = 1 +stretch_mode = 5 + +[node name="VSeparator" type="VSeparator" parent="HBoxContainer"] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +auto_translate = false + +[node name="Label" type="Label" parent="HBoxContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +text = "Atlas Chopper" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 4 + +[node name="LineEdit" type="LineEdit" parent="HBoxContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "H Count" + +[node name="LineEdit2" type="LineEdit" parent="HBoxContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "V Count" + +[node name="Button" type="Button" parent="HBoxContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 4 +text = "Chop chop chop!!!" + +[node name="Control" type="Control" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_filter = 2 + +[connection signal="pressed" from="HBoxContainer/VBoxContainer/Button" to="." method="_on_Button_pressed"] diff --git a/cube.tscn b/cube.tscn new file mode 100644 index 0000000..635ede2 --- /dev/null +++ b/cube.tscn @@ -0,0 +1,23 @@ +[gd_scene load_steps=4 format=3 uid="uid://bw2jw3cwasqsm"] + +[sub_resource type="BoxMesh" id="BoxMesh_xc3wn"] +size = Vector3(2, 1, 2) + +[sub_resource type="NavigationMesh" id="NavigationMesh_jbd7x"] +vertices = PackedVector3Array(-1, 0.5, 1, 1, 0.5, -1, 1, 0.5, 1, -1, 0.5, -1, -1, -0.5, 1, 1, -0.5, -1, 1, -0.5, 1, -1, -0.5, -1, 1, 0.5, 1, -1, 0.5, -1, 1, 0.5, -1, -1, 0.5, 1, 1, -0.5, 1, -1, -0.5, -1, 1, -0.5, -1, -1, -0.5, 1, 1, 0.5, 1, -1, -0.5, 1, -1, 0.5, 1, 1, -0.5, 1, 1, 0.5, -1, -1, -0.5, -1, -1, 0.5, -1, 1, -0.5, -1) +polygons = [PackedInt32Array(0, 2, 4), PackedInt32Array(2, 6, 4), PackedInt32Array(1, 3, 5), PackedInt32Array(3, 7, 5), PackedInt32Array(8, 10, 12), PackedInt32Array(10, 14, 12), PackedInt32Array(9, 11, 13), PackedInt32Array(11, 15, 13), PackedInt32Array(16, 18, 20), PackedInt32Array(18, 22, 20), PackedInt32Array(17, 19, 21), PackedInt32Array(19, 23, 21)] + +[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_wd2d1"] +data = PackedVector3Array(-1, 0.5, 1, 1, 0.5, 1, -1, -0.5, 1, 1, 0.5, 1, 1, -0.5, 1, -1, -0.5, 1, 1, 0.5, -1, -1, 0.5, -1, 1, -0.5, -1, -1, 0.5, -1, -1, -0.5, -1, 1, -0.5, -1, 1, 0.5, 1, 1, 0.5, -1, 1, -0.5, 1, 1, 0.5, -1, 1, -0.5, -1, 1, -0.5, 1, -1, 0.5, -1, -1, 0.5, 1, -1, -0.5, -1, -1, 0.5, 1, -1, -0.5, 1, -1, -0.5, -1, 1, 0.5, 1, -1, 0.5, 1, 1, 0.5, -1, -1, 0.5, 1, -1, 0.5, -1, 1, 0.5, -1, -1, -0.5, 1, 1, -0.5, 1, -1, -0.5, -1, 1, -0.5, 1, 1, -0.5, -1, -1, -0.5, -1) + +[node name="MeshInstance3D2" type="MeshInstance3D"] +mesh = SubResource("BoxMesh_xc3wn") +skeleton = NodePath("") + +[node name="NavigationRegion3D" type="NavigationRegion3D" parent="."] +navigation_mesh = SubResource("NavigationMesh_jbd7x") + +[node name="StaticBody3D" type="StaticBody3D" parent="."] + +[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D"] +shape = SubResource("ConcavePolygonShape3D_wd2d1") diff --git a/example/Items/item_icons/items.png b/example/Items/item_icons/items.png new file mode 100644 index 0000000..d2a6f64 Binary files /dev/null and b/example/Items/item_icons/items.png differ diff --git a/example/Items/item_icons/items.png.import b/example/Items/item_icons/items.png.import new file mode 100644 index 0000000..d94184a --- /dev/null +++ b/example/Items/item_icons/items.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dwi4ioxeauoc4" +path="res://.godot/imported/items.png-d10b6b2feac7b3334582afee422be338.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://example/Items/item_icons/items.png" +dest_files=["res://.godot/imported/items.png-d10b6b2feac7b3334582afee422be338.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 diff --git a/example/Items/item_type.gd b/example/Items/item_type.gd new file mode 100644 index 0000000..c436d63 --- /dev/null +++ b/example/Items/item_type.gd @@ -0,0 +1,32 @@ +extends Resource + +enum SlotType { + SMALL, + LARGE, + EQUIPMENT, + QUEST, + POTION, + AMMO, + CURRENCY, + FUEL, + CRAFTING, + E_MAINHAND, + E_OFFHAND, + E_HELM, + E_CHEST, + E_BELT, + E_HANDS, + E_FEET, + E_RING, + E_NECK, +} +@export var name := "" +@export_multiline var description := "" +@export var max_stack_count := 1 +@export var in_inventory_width := 1 +@export var in_inventory_height := 1 +@export var texture : Texture +@export var mesh : Mesh + +@export var slot_flags : SlotType = SlotType.SMALL +@export var default_properties : Dictionary diff --git a/example/Items/item_type.gd.uid b/example/Items/item_type.gd.uid new file mode 100644 index 0000000..dfb1d98 --- /dev/null +++ b/example/Items/item_type.gd.uid @@ -0,0 +1 @@ +uid://bepmdx7vwqi7s diff --git a/example/Items/items/arrows.tres b/example/Items/items/arrows.tres new file mode 100644 index 0000000..b5558a3 --- /dev/null +++ b/example/Items/items/arrows.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://c65l1w3756rlu"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_npnns"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_npnns") +region = Rect2(12, 24, 24, 12) + +[resource] +script = ExtResource("2") +name = "arrows" +description = "desc_arrows" +max_stack_count = 20 +in_inventory_width = 2 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 5 +default_properties = {} diff --git a/example/Items/items/belt_1.tres b/example/Items/items/belt_1.tres new file mode 100644 index 0000000..f797bab --- /dev/null +++ b/example/Items/items/belt_1.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://d2gb438d6vtlg"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_4rd1p"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_4rd1p") +region = Rect2(0, 156, 24, 12) + +[resource] +script = ExtResource("1") +name = "belt_1" +description = "desc_belt_1" +max_stack_count = 1 +in_inventory_width = 2 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 13 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"dodgerate": 12.0 +} +} diff --git a/example/Items/items/belt_2.tres b/example/Items/items/belt_2.tres new file mode 100644 index 0000000..631da08 --- /dev/null +++ b/example/Items/items/belt_2.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://c158a1idjr28m"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_laq2t"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_laq2t") +region = Rect2(24, 156, 24, 12) + +[resource] +script = ExtResource("1") +name = "belt_2" +description = "desc_belt_2" +max_stack_count = 1 +in_inventory_width = 2 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 13 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"health_regen": 2.0 +} +} diff --git a/example/Items/items/chestplate_1.tres b/example/Items/items/chestplate_1.tres new file mode 100644 index 0000000..c3c6495 --- /dev/null +++ b/example/Items/items/chestplate_1.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://ubapirchpsp"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_cwgb2"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_cwgb2") +region = Rect2(0, 120, 24, 36) + +[resource] +script = ExtResource("1") +name = "chestplate_1" +description = "desc_chestplate_1" +max_stack_count = 1 +in_inventory_width = 2 +in_inventory_height = 3 +texture = SubResource("1") +slot_flags = 12 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"defense": 24.0 +} +} diff --git a/example/Items/items/chestplate_2.tres b/example/Items/items/chestplate_2.tres new file mode 100644 index 0000000..516b0ab --- /dev/null +++ b/example/Items/items/chestplate_2.tres @@ -0,0 +1,29 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://nquj8y70tdy1"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_fdlcg"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_fdlcg") +region = Rect2(24, 120, 24, 36) + +[resource] +script = ExtResource("1") +name = "chestplate_2" +description = "desc_chestplate_2" +max_stack_count = 1 +in_inventory_width = 2 +in_inventory_height = 3 +texture = SubResource("1") +slot_flags = 12 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"defense": 16.0, +"dodgerate": 16.0 +} +} diff --git a/example/Items/items/coin_gold.tres b/example/Items/items/coin_gold.tres new file mode 100644 index 0000000..b4d0ff8 --- /dev/null +++ b/example/Items/items/coin_gold.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://cqbrojgnmjvil"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_lbcs7"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_lbcs7") +region = Rect2(0, 0, 12, 12) + +[resource] +script = ExtResource("2") +name = "coin_gold" +description = "desc_coin_gold" +max_stack_count = 100 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 6 +default_properties = {} diff --git a/example/Items/items/coin_purple.tres b/example/Items/items/coin_purple.tres new file mode 100644 index 0000000..624c204 --- /dev/null +++ b/example/Items/items/coin_purple.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://4amkkv73m0lc"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_gphlp"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_gphlp") +region = Rect2(0, 12, 12, 12) + +[resource] +script = ExtResource("2") +name = "coin_purple" +description = "desc_coin_purple" +max_stack_count = 100 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 6 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1) +} diff --git a/example/Items/items/feather.tres b/example/Items/items/feather.tres new file mode 100644 index 0000000..29cd487 --- /dev/null +++ b/example/Items/items/feather.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://csj85mouew67r"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_vvaq3"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_vvaq3") +region = Rect2(84, 24, 12, 12) + +[resource] +script = ExtResource("2") +name = "feather" +description = "desc_feather" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = {} diff --git a/example/Items/items/gem_blue.tres b/example/Items/items/gem_blue.tres new file mode 100644 index 0000000..77e330d --- /dev/null +++ b/example/Items/items/gem_blue.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://ghiwkmadh0i"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_io53q"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_io53q") +region = Rect2(84, 36, 12, 12) + +[resource] +script = ExtResource("2") +name = "gem_blue" +description = "desc_gem_blue" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = {} diff --git a/example/Items/items/head_helmet.tres b/example/Items/items/head_helmet.tres new file mode 100644 index 0000000..5e2e470 --- /dev/null +++ b/example/Items/items/head_helmet.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://dmgt12il41ul7"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_1ooxf"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_1ooxf") +region = Rect2(0, 168, 24, 24) + +[resource] +script = ExtResource("1") +name = "head_helmet" +description = "desc_head_helmet" +max_stack_count = 1 +in_inventory_width = 2 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 11 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"defense": 8.0 +} +} diff --git a/example/Items/items/head_wizardhat.tres b/example/Items/items/head_wizardhat.tres new file mode 100644 index 0000000..b691150 --- /dev/null +++ b/example/Items/items/head_wizardhat.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://bwtgji4rkgc5"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_6ygl4"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_6ygl4") +region = Rect2(24, 168, 24, 24) + +[resource] +script = ExtResource("1") +name = "head_wizardhat" +description = "desc_head_wizardhat" +max_stack_count = 1 +in_inventory_width = 2 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 11 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"magic_regen": 2.0 +} +} diff --git a/example/Items/items/herb.tres b/example/Items/items/herb.tres new file mode 100644 index 0000000..c042731 --- /dev/null +++ b/example/Items/items/herb.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://v7imonnsq6xx"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_awqqy"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_awqqy") +region = Rect2(12, 36, 24, 12) + +[resource] +script = ExtResource("2") +name = "herb" +description = "desc_herb" +max_stack_count = 20 +in_inventory_width = 2 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = {} diff --git a/example/Items/items/leather.tres b/example/Items/items/leather.tres new file mode 100644 index 0000000..c202731 --- /dev/null +++ b/example/Items/items/leather.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://okiwvbkwltf2"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_v5nv2"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_v5nv2") +region = Rect2(60, 24, 24, 12) + +[resource] +script = ExtResource("2") +name = "leather" +description = "desc_leather" +max_stack_count = 20 +in_inventory_width = 2 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = {} diff --git a/example/Items/items/magic_crystal.tres b/example/Items/items/magic_crystal.tres new file mode 100644 index 0000000..d06faa7 --- /dev/null +++ b/example/Items/items/magic_crystal.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://d4eo3up2esgao"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_l77qe"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_l77qe") +region = Rect2(0, 24, 12, 24) + +[resource] +script = ExtResource("2") +name = "magic_crystal" +description = "desc_magic_crystal" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 8 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1) +} diff --git a/example/Items/items/melee_battleaxe.tres b/example/Items/items/melee_battleaxe.tres new file mode 100644 index 0000000..9a1f21b --- /dev/null +++ b/example/Items/items/melee_battleaxe.tres @@ -0,0 +1,29 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://vi43b1o26w60"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_glg1x"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_glg1x") +region = Rect2(12, 72, 12, 48) + +[resource] +script = ExtResource("2") +name = "melee_battleaxe" +description = "desc_melee_battleaxe" +max_stack_count = 1 +in_inventory_width = 1 +in_inventory_height = 4 +texture = SubResource("1") +slot_flags = 9 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"weapon_damage": 8.0, +"weapon_speed": 0.8 +} +} diff --git a/example/Items/items/melee_sword.tres b/example/Items/items/melee_sword.tres new file mode 100644 index 0000000..f10f91d --- /dev/null +++ b/example/Items/items/melee_sword.tres @@ -0,0 +1,29 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://cidvqmpxobgv7"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_qyy4c"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_qyy4c") +region = Rect2(0, 72, 12, 36) + +[resource] +script = ExtResource("2") +name = "melee_sword" +description = "desc_melee_sword" +max_stack_count = 1 +in_inventory_width = 1 +in_inventory_height = 3 +texture = SubResource("1") +slot_flags = 9 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"weapon_damage": 4.0, +"weapon_speed": 1.5 +} +} diff --git a/example/Items/items/metalscrap_copper.tres b/example/Items/items/metalscrap_copper.tres new file mode 100644 index 0000000..c267926 --- /dev/null +++ b/example/Items/items/metalscrap_copper.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://d2vm3srqwars"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_w6v7m"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_w6v7m") +region = Rect2(48, 24, 12, 12) + +[resource] +script = ExtResource("2") +name = "metalscrap_copper" +description = "desc_metalscrap_copper" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = {} diff --git a/example/Items/items/metalscrap_gold.tres b/example/Items/items/metalscrap_gold.tres new file mode 100644 index 0000000..b20a5ac --- /dev/null +++ b/example/Items/items/metalscrap_gold.tres @@ -0,0 +1,24 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://b45up1xg1qnlo"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_eoswi"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_eoswi") +region = Rect2(36, 36, 12, 12) + +[resource] +script = ExtResource("2") +name = "metalscrap_gold" +description = "desc_metalscrap_gold" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 10.0 +} +} diff --git a/example/Items/items/metalscrap_iron.tres b/example/Items/items/metalscrap_iron.tres new file mode 100644 index 0000000..5c4064f --- /dev/null +++ b/example/Items/items/metalscrap_iron.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://dyb3w176j3sco"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_61lme"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_61lme") +region = Rect2(36, 24, 12, 12) + +[resource] +script = ExtResource("2") +name = "metalscrap_iron" +description = "desc_metalscrap_iron" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = {} diff --git a/example/Items/items/metalscrap_wyvernite.tres b/example/Items/items/metalscrap_wyvernite.tres new file mode 100644 index 0000000..d7f76cd --- /dev/null +++ b/example/Items/items/metalscrap_wyvernite.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://desvy1h36yy1s"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_bon0y"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_bon0y") +region = Rect2(48, 36, 12, 12) + +[resource] +script = ExtResource("2") +name = "metalscrap_wyvernite" +description = "desc_metalscrap_wyvernite" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1) +} diff --git a/example/Items/items/potion_blue.tres b/example/Items/items/potion_blue.tres new file mode 100644 index 0000000..fc40f4f --- /dev/null +++ b/example/Items/items/potion_blue.tres @@ -0,0 +1,24 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://b0l5g2tgwvm3b"] + +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="1"] +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("1") +region = Rect2(36, 0, 12, 24) + +[resource] +script = ExtResource("2") +name = "potion_blue" +description = "desc_potion_blue" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 4 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 5 +} +} diff --git a/example/Items/items/potion_purple.tres b/example/Items/items/potion_purple.tres new file mode 100644 index 0000000..f4170f6 --- /dev/null +++ b/example/Items/items/potion_purple.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://cbrsfa22sudf5"] + +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="1"] +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("1") +region = Rect2(24, 0, 12, 24) + +[resource] +script = ExtResource("2") +name = "potion_purple" +description = "desc_potion_purple" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 4 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1) +} diff --git a/example/Items/items/potion_red.tres b/example/Items/items/potion_red.tres new file mode 100644 index 0000000..4ee5e9e --- /dev/null +++ b/example/Items/items/potion_red.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://crq178t8cp2g7"] + +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="1"] +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("1") +region = Rect2(12, 0, 12, 24) + +[resource] +script = ExtResource("2") +name = "potion_red" +description = "desc_potion_red" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 4 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1) +} diff --git a/example/Items/items/ring_1.tres b/example/Items/items/ring_1.tres new file mode 100644 index 0000000..552bd22 --- /dev/null +++ b/example/Items/items/ring_1.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://d1sgj2djflire"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_7y5px"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_7y5px") +region = Rect2(0, 192, 12, 12) + +[resource] +script = ExtResource("1") +name = "ring_1" +description = "desc_ring_1" +max_stack_count = 1 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 16 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"dodgerate": 8.0 +} +} diff --git a/example/Items/items/ring_2.tres b/example/Items/items/ring_2.tres new file mode 100644 index 0000000..38dfa41 --- /dev/null +++ b/example/Items/items/ring_2.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://dwsqjeolbi2j6"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="1"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_a2wrg"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_a2wrg") +region = Rect2(12, 192, 12, 12) + +[resource] +script = ExtResource("1") +name = "ring_2" +description = "desc_ring_2" +max_stack_count = 1 +in_inventory_width = 1 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 16 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"health": 8.0 +} +} diff --git a/example/Items/items/scroll_enchant.tres b/example/Items/items/scroll_enchant.tres new file mode 100644 index 0000000..e67fea9 --- /dev/null +++ b/example/Items/items/scroll_enchant.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://7vy4rqrqnt4q"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_oismr"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_oismr") +region = Rect2(96, 24, 12, 24) + +[resource] +script = ExtResource("2") +name = "scroll_enchant" +description = "desc_scroll_enchant" +max_stack_count = 20 +in_inventory_width = 1 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 6 +default_properties = { +"back_color": Color(0.67451, 0.270588, 0.972549, 1) +} diff --git a/example/Items/items/wand_purple.tres b/example/Items/items/wand_purple.tres new file mode 100644 index 0000000..f711f79 --- /dev/null +++ b/example/Items/items/wand_purple.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://ckgvaqimbvnv8"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_8lhvp"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_8lhvp") +region = Rect2(0, 48, 12, 24) + +[resource] +script = ExtResource("2") +name = "wand_purple" +description = "desc_wand_purple" +max_stack_count = 1 +in_inventory_width = 1 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 9 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"magic": 16.0 +} +} diff --git a/example/Items/items/wand_red.tres b/example/Items/items/wand_red.tres new file mode 100644 index 0000000..8274f25 --- /dev/null +++ b/example/Items/items/wand_red.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://napa4vmvmphs"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_cihvk"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_cihvk") +region = Rect2(12, 48, 12, 24) + +[resource] +script = ExtResource("2") +name = "wand_red" +description = "desc_wand_red" +max_stack_count = 1 +in_inventory_width = 1 +in_inventory_height = 2 +texture = SubResource("1") +slot_flags = 9 +default_properties = { +"back_color": Color(1, 0.65098, 0, 1), +"price": { +"res://example/wyvernbox/item_types/consumable/coin_gold.tres": 50, +"res://example/wyvernbox/item_types/consumable/coin_purple.tres": 10 +}, +"stats": { +"spell_damage": 8.0 +} +} diff --git a/example/Items/items/wood.tres b/example/Items/items/wood.tres new file mode 100644 index 0000000..423b478 --- /dev/null +++ b/example/Items/items/wood.tres @@ -0,0 +1,19 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://uge4rk0vtwxs"] + +[ext_resource type="Script" path="res://example/Items/item_type.gd" id="2"] +[ext_resource type="Texture2D" uid="uid://dwi4ioxeauoc4" path="res://example/Items/item_icons/items.png" id="2_7ia04"] + +[sub_resource type="AtlasTexture" id="1"] +atlas = ExtResource("2_7ia04") +region = Rect2(60, 36, 24, 12) + +[resource] +script = ExtResource("2") +name = "wood" +description = "desc_wood" +max_stack_count = 20 +in_inventory_width = 2 +in_inventory_height = 1 +texture = SubResource("1") +slot_flags = 8 +default_properties = {} diff --git a/example/Random Upgrades/icons/all_icons.png b/example/Random Upgrades/icons/all_icons.png new file mode 100644 index 0000000..71e7fe2 Binary files /dev/null and b/example/Random Upgrades/icons/all_icons.png differ diff --git a/example/Random Upgrades/icons/all_icons.png.import b/example/Random Upgrades/icons/all_icons.png.import new file mode 100644 index 0000000..40d9e97 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b7e3wp7i33ye5" +path="res://.godot/imported/all_icons.png-28909f8bd099d79f5d095eb93a9167e6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://example/Random Upgrades/icons/all_icons.png" +dest_files=["res://.godot/imported/all_icons.png-28909f8bd099d79f5d095eb93a9167e6.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 diff --git a/example/Random Upgrades/icons/all_icons/all_icons_1.tres b/example/Random Upgrades/icons/all_icons/all_icons_1.tres new file mode 100644 index 0000000..d3a38a3 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_1.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://c3bx6kf7frbwk"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1"] + +[resource] +atlas = ExtResource("1") +region = Rect2(0, 0, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_10.tres b/example/Random Upgrades/icons/all_icons/all_icons_10.tres new file mode 100644 index 0000000..4131f8c --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_10.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://cak6lra5ej68c"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_6pmrx"] + +[resource] +atlas = ExtResource("1_6pmrx") +region = Rect2(64, 128, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_11.tres b/example/Random Upgrades/icons/all_icons/all_icons_11.tres new file mode 100644 index 0000000..5ae6a28 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_11.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://dkc8d2p0xbl1n"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_lk0lg"] + +[resource] +atlas = ExtResource("1_lk0lg") +region = Rect2(128, 128, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_12.tres b/example/Random Upgrades/icons/all_icons/all_icons_12.tres new file mode 100644 index 0000000..1397909 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_12.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://ciiykhulvckp7"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_fd56b"] + +[resource] +atlas = ExtResource("1_fd56b") +region = Rect2(192, 128, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_13.tres b/example/Random Upgrades/icons/all_icons/all_icons_13.tres new file mode 100644 index 0000000..cbabc98 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_13.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://dki1d3uksoyfj"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_ds6ve"] + +[resource] +atlas = ExtResource("1_ds6ve") +region = Rect2(0, 192, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_14.tres b/example/Random Upgrades/icons/all_icons/all_icons_14.tres new file mode 100644 index 0000000..303ee64 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_14.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://cpenn4qsfhx28"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_icesd"] + +[resource] +atlas = ExtResource("1_icesd") +region = Rect2(64, 192, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_15.tres b/example/Random Upgrades/icons/all_icons/all_icons_15.tres new file mode 100644 index 0000000..3de416c --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_15.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://cm6cb8uou75x0"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_mlqxi"] + +[resource] +atlas = ExtResource("1_mlqxi") +region = Rect2(128, 192, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_16.tres b/example/Random Upgrades/icons/all_icons/all_icons_16.tres new file mode 100644 index 0000000..fe9075e --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_16.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://0c7ngrkwn42u"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_jk82p"] + +[resource] +atlas = ExtResource("1_jk82p") +region = Rect2(192, 192, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_2.tres b/example/Random Upgrades/icons/all_icons/all_icons_2.tres new file mode 100644 index 0000000..405fe32 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_2.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://dfpwu4ra3fxgx"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1"] + +[resource] +atlas = ExtResource("1") +region = Rect2(64, 0, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_3.tres b/example/Random Upgrades/icons/all_icons/all_icons_3.tres new file mode 100644 index 0000000..8bc87b0 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_3.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://d38giyxvkhl6g"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1"] + +[resource] +atlas = ExtResource("1") +region = Rect2(128, 0, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_4.tres b/example/Random Upgrades/icons/all_icons/all_icons_4.tres new file mode 100644 index 0000000..517e84f --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_4.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://cluvoehgeqmcu"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1"] + +[resource] +atlas = ExtResource("1") +region = Rect2(192, 0, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_5.tres b/example/Random Upgrades/icons/all_icons/all_icons_5.tres new file mode 100644 index 0000000..8363f7b --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_5.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://djjpa8lluue1g"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1"] + +[resource] +atlas = ExtResource("1") +region = Rect2(0, 64, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_6.tres b/example/Random Upgrades/icons/all_icons/all_icons_6.tres new file mode 100644 index 0000000..df97e79 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_6.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://butx3l1jdcgcc"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_em1jn"] + +[resource] +atlas = ExtResource("1_em1jn") +region = Rect2(64, 64, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_7.tres b/example/Random Upgrades/icons/all_icons/all_icons_7.tres new file mode 100644 index 0000000..bfe8fdb --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_7.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://dfhgifwrrigrw"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_bpiay"] + +[resource] +atlas = ExtResource("1_bpiay") +region = Rect2(128, 64, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_8.tres b/example/Random Upgrades/icons/all_icons/all_icons_8.tres new file mode 100644 index 0000000..640155a --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_8.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://dacww8ptt8uyo"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_mbxiu"] + +[resource] +atlas = ExtResource("1_mbxiu") +region = Rect2(192, 64, 64, 64) diff --git a/example/Random Upgrades/icons/all_icons/all_icons_9.tres b/example/Random Upgrades/icons/all_icons/all_icons_9.tres new file mode 100644 index 0000000..0c97341 --- /dev/null +++ b/example/Random Upgrades/icons/all_icons/all_icons_9.tres @@ -0,0 +1,7 @@ +[gd_resource type="AtlasTexture" load_steps=2 format=3 uid="uid://dbbgxcs806sy8"] + +[ext_resource type="Texture2D" uid="uid://b7e3wp7i33ye5" path="res://example/Random Upgrades/icons/all_icons.png" id="1_bw3gq"] + +[resource] +atlas = ExtResource("1_bw3gq") +region = Rect2(0, 128, 64, 64) diff --git a/example/Random Upgrades/new scene.tscn b/example/Random Upgrades/new scene.tscn new file mode 100644 index 0000000..cf94da5 --- /dev/null +++ b/example/Random Upgrades/new scene.tscn @@ -0,0 +1,31 @@ +[gd_scene format=3 uid="uid://b4cix5ebtpdbf"] + +[node name="Node2D" type="Node2D"] + +[node name="ColorRect" type="ColorRect" parent="."] +offset_left = 363.0 +offset_top = 83.0 +offset_right = 718.0 +offset_bottom = 632.0 +color = Color(0, 1, 0.0156863, 1) + +[node name="ColorRect2" type="ColorRect" parent="."] +offset_left = 833.0 +offset_top = 304.0 +offset_right = 1095.0 +offset_bottom = 653.0 +color = Color(0, 0.905882, 1, 1) + +[node name="ColorRect3" type="ColorRect" parent="."] +offset_left = 553.0 +offset_top = 491.0 +offset_right = 929.0 +offset_bottom = 770.0 +color = Color(0, 0.0156863, 1, 1) + +[node name="ColorRect4" type="ColorRect" parent="."] +offset_left = 746.0 +offset_top = 397.0 +offset_right = 1077.0 +offset_bottom = 632.0 +color = Color(0.686275, 0, 1, 1) diff --git a/example/Random Upgrades/upgrade_data.gd b/example/Random Upgrades/upgrade_data.gd new file mode 100644 index 0000000..915857c --- /dev/null +++ b/example/Random Upgrades/upgrade_data.gd @@ -0,0 +1,30 @@ +@tool +class_name UpgradeData +extends Resource + +enum Attributes { + Strength = 0, + Magic, + Endurance, + Agility, + Luck, + Mastery = 128, +} + +@export var color1 := Color.WHITE +@export var max_duplicates := 0 +@export var tags : Array[String] +@export_enum("Weapon", "Passive", "Mastery") var type := 0 +@export var attributes : Array[Attributes] +@export var icon : Texture +@export var custom_scene : PackedScene +@export var prerequisites : Array[UpgradeData] +@export var color2 := Color.WHITE +@export var base_weight := 10.0 +@export var is_notable := false +@export_multiline var multiplier_per_tag := "" +@export_multiline var multiplier_if_tag_present := "" +@export_multiline var multiplier_if_tag_not_present := "" +@export_multiline var max_tags_present := "" +@export var list_item_delimeter := " " +@export var list_row_delimeter := ";" diff --git a/example/Random Upgrades/upgrade_data.gd.uid b/example/Random Upgrades/upgrade_data.gd.uid new file mode 100644 index 0000000..13094fa --- /dev/null +++ b/example/Random Upgrades/upgrade_data.gd.uid @@ -0,0 +1 @@ +uid://dsvs6vfu3bipu diff --git a/example/Random Upgrades/upgrade_data_weapon.gd b/example/Random Upgrades/upgrade_data_weapon.gd new file mode 100644 index 0000000..51b6420 --- /dev/null +++ b/example/Random Upgrades/upgrade_data_weapon.gd @@ -0,0 +1,16 @@ +@tool +extends "res://example/Random Upgrades/upgrade_data.gd" + +@export var weapon_damage := 0.0 +@export var weapon_cooldown := 0.0 +@export var weapon_dps := 0.0: + set(v): + weapon_damage = v * weapon_cooldown + get: + return weapon_damage / weapon_cooldown if weapon_cooldown != 0.0 else 0.0 + + +func _validate_property(property: Dictionary) -> void: + if property.name == &"weapon_dps": + # Show in inspector, but don't save into resource file. + property.usage = PROPERTY_USAGE_EDITOR diff --git a/example/Random Upgrades/upgrade_data_weapon.gd.uid b/example/Random Upgrades/upgrade_data_weapon.gd.uid new file mode 100644 index 0000000..c0c167f --- /dev/null +++ b/example/Random Upgrades/upgrade_data_weapon.gd.uid @@ -0,0 +1 @@ +uid://c241cayvjxjk5 diff --git a/example/Random Upgrades/upgrades/elemental.tres b/example/Random Upgrades/upgrades/elemental.tres new file mode 100644 index 0000000..b0a6db6 --- /dev/null +++ b/example/Random Upgrades/upgrades/elemental.tres @@ -0,0 +1,25 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=3 format=3 uid="uid://8m6y2o6tbmpn"] + +[ext_resource type="Texture2D" uid="uid://butx3l1jdcgcc" path="res://example/Random Upgrades/icons/all_icons/all_icons_6.tres" id="1_utkae"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2"] + +[resource] +resource_name = "Upgrade: Elemental Damage" +script = ExtResource("2") +color1 = Color(1, 1, 1, 1) +max_duplicates = 9 +tags = Array[String](["elemental"]) +type = 1 +attributes = Array[int]([1]) +icon = ExtResource("1_utkae") +prerequisites = Array[ExtResource("2")]([]) +color2 = Color(0.964706, 0.298039, 0.298039, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "elemental 0" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/health.tres b/example/Random Upgrades/upgrades/health.tres new file mode 100644 index 0000000..3cce2ba --- /dev/null +++ b/example/Random Upgrades/upgrades/health.tres @@ -0,0 +1,25 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=3 format=3 uid="uid://dys7hpijn82t0"] + +[ext_resource type="Texture2D" uid="uid://c3bx6kf7frbwk" path="res://example/Random Upgrades/icons/all_icons/all_icons_1.tres" id="1"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2"] + +[resource] +resource_name = "Upgrade: Health" +script = ExtResource("2") +color1 = Color(1, 1, 1, 1) +max_duplicates = 9 +tags = Array[String](["health", "melee"]) +type = 1 +attributes = Array[int]([2]) +icon = ExtResource("1") +prerequisites = Array[ExtResource("2")]([]) +color2 = Color(0.129412, 1, 0.243137, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "strength 1.5 melee 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/mastery_magic.tres b/example/Random Upgrades/upgrades/mastery_magic.tres new file mode 100644 index 0000000..e975c5e --- /dev/null +++ b/example/Random Upgrades/upgrades/mastery_magic.tres @@ -0,0 +1,29 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=7 format=3 uid="uid://2totlbwc40e8"] + +[ext_resource type="Texture2D" uid="uid://djjpa8lluue1g" path="res://example/Random Upgrades/icons/all_icons/all_icons_5.tres" id="1_ardng"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2"] +[ext_resource type="Resource" uid="uid://rjxr4qtfc6qd" path="res://example/Random Upgrades/upgrades/weapons/weapon_fireball.tres" id="2_485ad"] +[ext_resource type="Resource" uid="uid://djqq1lqaevth5" path="res://example/Random Upgrades/upgrades/weapons/weapon_blizzard.tres" id="3_xnxxn"] +[ext_resource type="Resource" uid="uid://b0kdw067vtgvn" path="res://example/Random Upgrades/upgrades/weapons/weapon_lightning.tres" id="4_kn0kg"] +[ext_resource type="Resource" uid="uid://8m6y2o6tbmpn" path="res://example/Random Upgrades/upgrades/elemental.tres" id="6_shqeu"] + +[resource] +resource_name = "Mastery: Magic" +script = ExtResource("2") +color1 = Color(1, 0.847059, 0.160784, 1) +max_duplicates = 9 +tags = Array[String](["magic", "mastery"]) +type = 2 +attributes = Array[int]([1, 1, 4, 128]) +icon = ExtResource("1_ardng") +prerequisites = Array[ExtResource("2")]([ExtResource("2_485ad"), ExtResource("3_xnxxn"), ExtResource("4_kn0kg"), ExtResource("6_shqeu")]) +color2 = Color(0.407843, 0.192157, 0.827451, 1) +base_weight = 1.0 +is_notable = true +multiplier_per_tag = "magic 1.2" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "magic 0" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/mastery_strength.tres b/example/Random Upgrades/upgrades/mastery_strength.tres new file mode 100644 index 0000000..8e8ec83 --- /dev/null +++ b/example/Random Upgrades/upgrades/mastery_strength.tres @@ -0,0 +1,29 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=7 format=3 uid="uid://d1suh8iai43st"] + +[ext_resource type="Texture2D" uid="uid://dfpwu4ra3fxgx" path="res://example/Random Upgrades/icons/all_icons/all_icons_2.tres" id="1_442ey"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2"] +[ext_resource type="Resource" uid="uid://cux4x0qopwiqk" path="res://example/Random Upgrades/upgrades/weapons/weapon_dagger.tres" id="2_kb33p"] +[ext_resource type="Resource" uid="uid://b78jqcpgef2ud" path="res://example/Random Upgrades/upgrades/weapons/weapon_axe.tres" id="3_tt25f"] +[ext_resource type="Resource" uid="uid://xl0yx8uq6bfp" path="res://example/Random Upgrades/upgrades/weapons/weapon_spear.tres" id="4_kpsn8"] +[ext_resource type="Resource" uid="uid://c6hsg3j74vm56" path="res://example/Random Upgrades/upgrades/up_strength.tres" id="6_gpjyk"] + +[resource] +resource_name = "Mastery: Strength" +script = ExtResource("2") +color1 = Color(1, 0.847059, 0.160784, 1) +max_duplicates = 9 +tags = Array[String](["strength", "mastery"]) +type = 2 +attributes = Array[int]([0, 0, 4, 128]) +icon = ExtResource("1_442ey") +prerequisites = Array[ExtResource("2")]([ExtResource("2_kb33p"), ExtResource("3_tt25f"), ExtResource("4_kpsn8"), ExtResource("6_gpjyk")]) +color2 = Color(0.992157, 0.941176, 0.2, 1) +base_weight = 1.0 +is_notable = true +multiplier_per_tag = "strength 1.2" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "strength 0" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/up_aoe.tres b/example/Random Upgrades/upgrades/up_aoe.tres new file mode 100644 index 0000000..85d2d6c --- /dev/null +++ b/example/Random Upgrades/upgrades/up_aoe.tres @@ -0,0 +1,26 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=4 format=3 uid="uid://2y7extlq12d5"] + +[ext_resource type="Texture2D" uid="uid://butx3l1jdcgcc" path="res://example/Random Upgrades/icons/all_icons/all_icons_6.tres" id="1_prpsx"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2"] +[ext_resource type="Resource" uid="uid://8m6y2o6tbmpn" path="res://example/Random Upgrades/upgrades/elemental.tres" id="3_xu25t"] + +[resource] +resource_name = "Upgrade: Area of Effect" +script = ExtResource("2") +color1 = Color(1, 1, 1, 1) +max_duplicates = 4 +tags = Array[String](["aoe"]) +type = 1 +attributes = Array[int]([3]) +icon = ExtResource("1_prpsx") +prerequisites = Array[ExtResource("2")]([ExtResource("3_xu25t")]) +color2 = Color(0.964706, 0.298039, 0.298039, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "aoe 0" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/up_magic.tres b/example/Random Upgrades/upgrades/up_magic.tres new file mode 100644 index 0000000..aabe734 --- /dev/null +++ b/example/Random Upgrades/upgrades/up_magic.tres @@ -0,0 +1,25 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=3 format=3 uid="uid://ce2kulhm7amkp"] + +[ext_resource type="Texture2D" uid="uid://djjpa8lluue1g" path="res://example/Random Upgrades/icons/all_icons/all_icons_5.tres" id="1_we1lq"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2"] + +[resource] +resource_name = "Upgrade: Magic" +script = ExtResource("2") +color1 = Color(1, 1, 1, 1) +max_duplicates = 9 +tags = Array[String](["magic"]) +type = 1 +attributes = Array[int]([1]) +icon = ExtResource("1_we1lq") +prerequisites = Array[ExtResource("2")]([]) +color2 = Color(0.188235, 0.45098, 0.901961, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "magic 0" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/up_movement_speed.tres b/example/Random Upgrades/upgrades/up_movement_speed.tres new file mode 100644 index 0000000..a1d6187 --- /dev/null +++ b/example/Random Upgrades/upgrades/up_movement_speed.tres @@ -0,0 +1,26 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=4 format=3 uid="uid://bn0r0bvk8fylt"] + +[ext_resource type="Texture2D" uid="uid://dfpwu4ra3fxgx" path="res://example/Random Upgrades/icons/all_icons/all_icons_2.tres" id="1_fy5ui"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2_gfl7s"] +[ext_resource type="Resource" uid="uid://c6hsg3j74vm56" path="res://example/Random Upgrades/upgrades/up_strength.tres" id="3_5v8xn"] + +[resource] +resource_name = "Upgrade: Strength" +script = ExtResource("2_gfl7s") +color1 = Color(1, 1, 1, 1) +max_duplicates = 9 +tags = Array[String](["strength"]) +type = 1 +attributes = Array[int]([0]) +icon = ExtResource("1_fy5ui") +prerequisites = Array[ExtResource("2_gfl7s")]([ExtResource("3_5v8xn")]) +color2 = Color(0.980392, 0.584314, 0.203922, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "strength 0" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/up_strength.tres b/example/Random Upgrades/upgrades/up_strength.tres new file mode 100644 index 0000000..85c443c --- /dev/null +++ b/example/Random Upgrades/upgrades/up_strength.tres @@ -0,0 +1,25 @@ +[gd_resource type="Resource" script_class="UpgradeData" load_steps=3 format=3 uid="uid://c6hsg3j74vm56"] + +[ext_resource type="Texture2D" uid="uid://dfpwu4ra3fxgx" path="res://example/Random Upgrades/icons/all_icons/all_icons_2.tres" id="1"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2"] + +[resource] +resource_name = "Upgrade: Strength" +script = ExtResource("2") +color1 = Color(1, 1, 1, 1) +max_duplicates = 9 +tags = Array[String](["strength"]) +type = 1 +attributes = Array[int]([0]) +icon = ExtResource("1") +prerequisites = Array[ExtResource("2")]([]) +color2 = Color(0.980392, 0.584314, 0.203922, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "strength 0" +max_tags_present = "" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_axe.tres b/example/Random Upgrades/upgrades/weapons/weapon_axe.tres new file mode 100644 index 0000000..5ba6e46 --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_axe.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://b78jqcpgef2ud"] + +[ext_resource type="Texture2D" uid="uid://d38giyxvkhl6g" path="res://example/Random Upgrades/icons/all_icons/all_icons_3.tres" id="1_1nxl6"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_646el"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2_w4j2j"] + +[resource] +resource_name = "Weapon: Axe" +script = ExtResource("1_646el") +weapon_damage = 4.0 +weapon_cooldown = 6.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["strength", "melee", "weapon"]) +type = 0 +attributes = Array[int]([0, 2]) +icon = ExtResource("1_1nxl6") +prerequisites = Array[ExtResource("2_w4j2j")]([]) +color2 = Color(0.980392, 0.584314, 0.203922, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "strength 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_blizzard.tres b/example/Random Upgrades/upgrades/weapons/weapon_blizzard.tres new file mode 100644 index 0000000..b4619a8 --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_blizzard.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://djqq1lqaevth5"] + +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_pewbv"] +[ext_resource type="Texture2D" uid="uid://cluvoehgeqmcu" path="res://example/Random Upgrades/icons/all_icons/all_icons_4.tres" id="1_sr0ui"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2_yatbe"] + +[resource] +resource_name = "Weapon: Blizzard" +script = ExtResource("1_pewbv") +weapon_damage = 4.0 +weapon_cooldown = 6.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["weapon", "magic", "elemental"]) +type = 0 +attributes = Array[int]([1, 2]) +icon = ExtResource("1_sr0ui") +prerequisites = Array[ExtResource("2_yatbe")]([]) +color2 = Color(0.189457, 0.452246, 0.902344, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "magic 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_chaos_blast.tres b/example/Random Upgrades/upgrades/weapons/weapon_chaos_blast.tres new file mode 100644 index 0000000..8c3bf36 --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_chaos_blast.tres @@ -0,0 +1,30 @@ +[gd_resource type="Resource" load_steps=5 format=3 uid="uid://60buw33oe30f"] + +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_02in4"] +[ext_resource type="Texture2D" uid="uid://cluvoehgeqmcu" path="res://example/Random Upgrades/icons/all_icons/all_icons_4.tres" id="1_6lnsr"] +[ext_resource type="PackedScene" uid="uid://b4cix5ebtpdbf" path="res://example/Random Upgrades/new scene.tscn" id="1_xh6ym"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="3_o4xc8"] + +[resource] +resource_name = "Weapon: Chaos Blast" +script = ExtResource("1_02in4") +weapon_damage = 12.0 +weapon_cooldown = 8.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["weapon", "magic", "projectile", "legendary"]) +type = 0 +attributes = Array[int]([1, 1, 1, 3]) +icon = ExtResource("1_6lnsr") +custom_scene = ExtResource("1_xh6ym") +prerequisites = Array[ExtResource("3_o4xc8")]([]) +color2 = Color(0.407843, 0.192157, 0.827451, 1) +base_weight = 1.0 +is_notable = true +multiplier_per_tag = "magic 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_dagger.tres b/example/Random Upgrades/upgrades/weapons/weapon_dagger.tres new file mode 100644 index 0000000..fa5abb3 --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_dagger.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://cux4x0qopwiqk"] + +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_birsa"] +[ext_resource type="Texture2D" uid="uid://d38giyxvkhl6g" path="res://example/Random Upgrades/icons/all_icons/all_icons_3.tres" id="1_sx5xe"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2_po4ym"] + +[resource] +resource_name = "Weapon: Daggers" +script = ExtResource("1_birsa") +weapon_damage = 4.0 +weapon_cooldown = 6.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["weapon", "strength", "projectile"]) +type = 0 +attributes = Array[int]([0, 3]) +icon = ExtResource("1_sx5xe") +prerequisites = Array[ExtResource("2_po4ym")]([]) +color2 = Color(0.980392, 0.584314, 0.203922, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "strength 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_fireball.tres b/example/Random Upgrades/upgrades/weapons/weapon_fireball.tres new file mode 100644 index 0000000..5f83bfa --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_fireball.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://rjxr4qtfc6qd"] + +[ext_resource type="Texture2D" uid="uid://cluvoehgeqmcu" path="res://example/Random Upgrades/icons/all_icons/all_icons_4.tres" id="1_5uqil"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_mehe7"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2_1ne1s"] + +[resource] +resource_name = "Weapon: Fireball" +script = ExtResource("1_mehe7") +weapon_damage = 4.0 +weapon_cooldown = 6.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["weapon", "magic", "projectile", "elemental"]) +type = 0 +attributes = Array[int]([1, 2]) +icon = ExtResource("1_5uqil") +prerequisites = Array[ExtResource("2_1ne1s")]([]) +color2 = Color(0.189457, 0.452246, 0.902344, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "magic 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_giga_sword.tres b/example/Random Upgrades/upgrades/weapons/weapon_giga_sword.tres new file mode 100644 index 0000000..2d54197 --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_giga_sword.tres @@ -0,0 +1,30 @@ +[gd_resource type="Resource" load_steps=5 format=3 uid="uid://c1mrcevxrm5kv"] + +[ext_resource type="PackedScene" uid="uid://b4cix5ebtpdbf" path="res://example/Random Upgrades/new scene.tscn" id="1_gppwv"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_ldwst"] +[ext_resource type="Texture2D" uid="uid://d38giyxvkhl6g" path="res://example/Random Upgrades/icons/all_icons/all_icons_3.tres" id="1_lir0x"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="3_8w1k7"] + +[resource] +resource_name = "Weapon: Giga Sword" +script = ExtResource("1_ldwst") +weapon_damage = 12.0 +weapon_cooldown = 8.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["weapon", "strength", "melee", "legendary"]) +type = 0 +attributes = Array[int]([0, 0, 0, 2]) +icon = ExtResource("1_lir0x") +custom_scene = ExtResource("1_gppwv") +prerequisites = Array[ExtResource("3_8w1k7")]([]) +color2 = Color(0.992157, 0.941176, 0.2, 1) +base_weight = 1.0 +is_notable = true +multiplier_per_tag = "strength 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_lightning.tres b/example/Random Upgrades/upgrades/weapons/weapon_lightning.tres new file mode 100644 index 0000000..0c6a534 --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_lightning.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://b0kdw067vtgvn"] + +[ext_resource type="Texture2D" uid="uid://cluvoehgeqmcu" path="res://example/Random Upgrades/icons/all_icons/all_icons_4.tres" id="1_jsyxk"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_yjf8q"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2_dskpw"] + +[resource] +resource_name = "Weapon: Lightning" +script = ExtResource("1_yjf8q") +weapon_damage = 4.0 +weapon_cooldown = 6.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["weapon", "magic", "elemental"]) +type = 0 +attributes = Array[int]([1, 3]) +icon = ExtResource("1_jsyxk") +prerequisites = Array[ExtResource("2_dskpw")]([]) +color2 = Color(0.189457, 0.452246, 0.902344, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "magic 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades/weapons/weapon_spear.tres b/example/Random Upgrades/upgrades/weapons/weapon_spear.tres new file mode 100644 index 0000000..a77ba27 --- /dev/null +++ b/example/Random Upgrades/upgrades/weapons/weapon_spear.tres @@ -0,0 +1,28 @@ +[gd_resource type="Resource" load_steps=4 format=3 uid="uid://xl0yx8uq6bfp"] + +[ext_resource type="Texture2D" uid="uid://d38giyxvkhl6g" path="res://example/Random Upgrades/icons/all_icons/all_icons_3.tres" id="1"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data_weapon.gd" id="1_rw2g6"] +[ext_resource type="Script" path="res://example/Random Upgrades/upgrade_data.gd" id="2_sqli1"] + +[resource] +resource_name = "Weapon: Spear" +script = ExtResource("1_rw2g6") +weapon_damage = 4.0 +weapon_cooldown = 6.0 +color1 = Color(0.635294, 0.760784, 1, 1) +max_duplicates = 1 +tags = Array[String](["weapon", "strength", "melee"]) +type = 0 +attributes = Array[int]([0, 3]) +icon = ExtResource("1") +prerequisites = Array[ExtResource("2_sqli1")]([]) +color2 = Color(0.980392, 0.584314, 0.203922, 1) +base_weight = 10.0 +is_notable = false +multiplier_per_tag = "strength 2.0" +multiplier_if_tag_present = "" +multiplier_if_tag_not_present = "" +max_tags_present = "weapon 4" +list_item_delimeter = " " +list_row_delimeter = " +" diff --git a/example/Random Upgrades/upgrades_csv/upgrades.csv b/example/Random Upgrades/upgrades_csv/upgrades.csv new file mode 100644 index 0000000..e5b477a --- /dev/null +++ b/example/Random Upgrades/upgrades_csv/upgrades.csv @@ -0,0 +1,33 @@ +resource_path;resource_name;color1;max_duplicates;tags;type;attributes;icon;custom_scene;prerequisites;color2;base_weight;is_notable;multiplier_per_tag;multiplier_if_tag_present;multiplier_if_tag_not_present;max_tags_present;list_item_delimeter;list_row_delimeter;weapon_damage;weapon_cooldown;weapon_dps +res://example/Random Upgrades/upgrades/elemental.tres;Upgrade: Elemental Damage;ffffffff;9;"[""elemental""]";Passive;[1];res://example/Random Upgrades/icons/all_icons/all_icons_6.tres;;[];f64c4cff;10;No;;;elemental 0;; ;" +";;; +res://example/Random Upgrades/upgrades/health.tres;Upgrade: Health;ffffffff;9;"[""health"", ""melee""]";Passive;[2];res://example/Random Upgrades/icons/all_icons/all_icons_1.tres;;[];21ff3eff;10;No;strength 1.5 melee 2.0;;;; ;" +";;; +res://example/Random Upgrades/upgrades/mastery_magic.tres;Mastery: Magic;ffd829ff;9;"[""magic"", ""mastery""]";Mastery;[1, 1, 4, 128];res://example/Random Upgrades/icons/all_icons/all_icons_5.tres;;[, , , ];6831d3ff;1;Yes;magic 1.2;;magic 0;; ;" +";;; +res://example/Random Upgrades/upgrades/mastery_strength.tres;Mastery: Strength;ffd829ff;9;"[""strength"", ""mastery""]";Mastery;[0, 0, 4, 128];res://example/Random Upgrades/icons/all_icons/all_icons_2.tres;;[, , , ];fdf033ff;1;Yes;strength 1.2;;strength 0;; ;" +";;; +res://example/Random Upgrades/upgrades/up_aoe.tres;Upgrade: Area of Effect;ffffffff;4;"[""aoe""]";Passive;[3];res://example/Random Upgrades/icons/all_icons/all_icons_6.tres;;[];f64c4cff;10;No;;;aoe 0;; ;" +";;; +res://example/Random Upgrades/upgrades/up_magic.tres;Upgrade: Magic;ffffffff;9;"[""magic""]";Passive;[1];res://example/Random Upgrades/icons/all_icons/all_icons_5.tres;;[];3073e6ff;10;No;;;magic 0;; ;" +";;; +res://example/Random Upgrades/upgrades/up_movement_speed.tres;Upgrade: Strength;ffffffff;9;"[""strength""]";Passive;[0];res://example/Random Upgrades/icons/all_icons/all_icons_2.tres;;[];fa9534ff;10;No;;;strength 0;; ;" +";;; +res://example/Random Upgrades/upgrades/up_strength.tres;Upgrade: Strength;ffffffff;9;"[""strength""]";Passive;[0];res://example/Random Upgrades/icons/all_icons/all_icons_2.tres;;[];fa9534ff;10;No;;;strength 0;; ;" +";;; +res://example/Random Upgrades/upgrades/weapons/weapon_axe.tres;Weapon: Axe;a2c2ffff;1;"[""strength"", ""melee"", ""weapon""]";Weapon;[0, 2];res://example/Random Upgrades/icons/all_icons/all_icons_3.tres;;[];fa9534ff;10;No;strength 2.0;;;weapon 4; ;" +";4;6;0.66666666666667 +res://example/Random Upgrades/upgrades/weapons/weapon_blizzard.tres;Weapon: Blizzard;a2c2ffff;1;"[""weapon"", ""magic"", ""elemental""]";Weapon;[1, 2];res://example/Random Upgrades/icons/all_icons/all_icons_4.tres;;[];3073e6ff;10;No;magic 2.0;;;weapon 4; ;" +";4;6;0.66666666666667 +res://example/Random Upgrades/upgrades/weapons/weapon_chaos_blast.tres;Weapon: Chaos Blast;a2c2ffff;1;"[""weapon"", ""magic"", ""projectile"", ""legendary""]";Weapon;[1, 1, 1, 3];res://example/Random Upgrades/icons/all_icons/all_icons_4.tres;res://example/Random Upgrades/new scene.tscn;[];6831d3ff;1;Yes;magic 2.0;;;weapon 4; ;" +";12;8;1.5 +res://example/Random Upgrades/upgrades/weapons/weapon_dagger.tres;Weapon: Daggers;a2c2ffff;1;"[""weapon"", ""strength"", ""projectile""]";Weapon;[0, 3];res://example/Random Upgrades/icons/all_icons/all_icons_3.tres;;[];fa9534ff;10;No;strength 2.0;;;weapon 4; ;" +";4;6;0.66666666666667 +res://example/Random Upgrades/upgrades/weapons/weapon_fireball.tres;Weapon: Fireball;a2c2ffff;1;"[""weapon"", ""magic"", ""projectile"", ""elemental""]";Weapon;[1, 2];res://example/Random Upgrades/icons/all_icons/all_icons_4.tres;;[];3073e6ff;10;No;magic 2.0;;;weapon 4; ;" +";4;6;0.66666666666667 +res://example/Random Upgrades/upgrades/weapons/weapon_giga_sword.tres;Weapon: Giga Sword;a2c2ffff;1;"[""weapon"", ""strength"", ""melee"", ""legendary""]";Weapon;[0, 0, 0, 2];res://example/Random Upgrades/icons/all_icons/all_icons_3.tres;res://example/Random Upgrades/new scene.tscn;[];fdf033ff;1;Yes;strength 2.0;;;weapon 4; ;" +";12;8;1.5 +res://example/Random Upgrades/upgrades/weapons/weapon_lightning.tres;Weapon: Lightning;a2c2ffff;1;"[""weapon"", ""magic"", ""elemental""]";Weapon;[1, 3];res://example/Random Upgrades/icons/all_icons/all_icons_4.tres;;[];3073e6ff;10;No;magic 2.0;;;weapon 4; ;" +";4;6;0.66666666666667 +res://example/Random Upgrades/upgrades/weapons/weapon_spear.tres;Weapon: Spear;a2c2ffff;1;"[""weapon"", ""strength"", ""melee""]";Weapon;[0, 3];res://example/Random Upgrades/icons/all_icons/all_icons_3.tres;;[];fa9534ff;10;No;strength 2.0;;;weapon 4; ;" +";4;6;0.66666666666667 diff --git a/example/Random Upgrades/upgrades_csv/upgrades.csv.import b/example/Random Upgrades/upgrades_csv/upgrades.csv.import new file mode 100644 index 0000000..8dd0c09 --- /dev/null +++ b/example/Random Upgrades/upgrades_csv/upgrades.csv.import @@ -0,0 +1,3 @@ +[remap] + +importer="keep" diff --git a/grid_map_test.gd b/grid_map_test.gd new file mode 100644 index 0000000..9d41027 --- /dev/null +++ b/grid_map_test.gd @@ -0,0 +1,30 @@ +extends GridMap + +var timer: float = 0 + +func _process(delta: float) -> void: + timer += delta + if timer > 1: + timer = 0 + test_path() + + if NavigationServer3D.get_maps().is_empty(): + return + + +func test_path() -> void: + if NavigationServer3D.get_maps().is_empty(): + return + + var map_rid: RID = NavigationServer3D.get_maps()[0] + + for region_rid in NavigationServer3D.map_get_regions(map_rid): + NavigationServer3D.region_set_travel_cost(region_rid, randf_range(0, 10)) + + var a: Vector3 = Vector3(1, 1, 1) + var b: Vector3 = Vector3(20,1,20) + var path: PackedVector3Array = NavigationServer3D.map_get_path(map_rid, a, b, true, 1) + + DebugDraw3D.draw_sphere(a, 0.5, Color.GREEN, 1) + DebugDraw3D.draw_sphere(b, 0.5, Color.RED, 1) + DebugDraw3D.draw_line_path(path, Color.YELLOW, 1) diff --git a/grid_map_test.gd.uid b/grid_map_test.gd.uid new file mode 100644 index 0000000..f999240 --- /dev/null +++ b/grid_map_test.gd.uid @@ -0,0 +1 @@ +uid://y8qfdplqsijx diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..1a10d58 --- /dev/null +++ b/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/icon.svg.import b/icon.svg.import new file mode 100644 index 0000000..cde2c14 --- /dev/null +++ b/icon.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c443xwndumhwx" +path.s3tc="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://icon.svg" +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +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=0 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/node_3d.tscn b/node_3d.tscn new file mode 100644 index 0000000..4db3589 --- /dev/null +++ b/node_3d.tscn @@ -0,0 +1,142 @@ +[gd_scene load_steps=18 format=3 uid="uid://bwftban1ppo17"] + +[ext_resource type="Script" uid="uid://y8qfdplqsijx" path="res://grid_map_test.gd" id="1_noarx"] +[ext_resource type="Script" uid="uid://ghsl3wni57q1" path="res://pathfinding_grid.gd" id="2_noarx"] + +[sub_resource type="PhysicalSkyMaterial" id="PhysicalSkyMaterial_4xowi"] + +[sub_resource type="Sky" id="Sky_a202f"] +sky_material = SubResource("PhysicalSkyMaterial_4xowi") + +[sub_resource type="Environment" id="Environment_noarx"] +background_mode = 2 +sky = SubResource("Sky_a202f") +tonemap_mode = 2 +ssr_enabled = true +ssr_fade_in = 0.060919 +ssr_fade_out = 0.0941018 +ssao_enabled = true +ssao_intensity = 0.65 +glow_enabled = true +volumetric_fog_density = 1.0 + +[sub_resource type="CameraAttributesPractical" id="CameraAttributesPractical_a0tk4"] + +[sub_resource type="BoxMesh" id="BoxMesh_a202f"] +size = Vector3(2, 1, 2) + +[sub_resource type="NavigationMesh" id="NavigationMesh_qra7f"] +vertices = PackedVector3Array(-0.75, 1, -0.75, -0.75, 1, 0.75, 0.75, 1, 0.75, 0.75, 1, -0.75) +polygons = [PackedInt32Array(3, 2, 0), PackedInt32Array(0, 2, 1)] +agent_radius = 0.2 +region_min_size = 1.0 + +[sub_resource type="Image" id="Image_noarx"] +data = { +"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 106, 106, 106, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 180, 180, 180, 255, 180, 180, 180, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 169, 169, 169, 255, 170, 170, 170, 255, 170, 170, 170, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 169, 169, 169, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 106, 106, 255, 106, 106, 106, 255, 106, 106, 106, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +"format": "RGBA8", +"height": 64, +"mipmaps": false, +"width": 64 +} + +[sub_resource type="ImageTexture" id="ImageTexture_a0tk4"] +image = SubResource("Image_noarx") + +[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_7h0kd"] +data = PackedVector3Array(-1, 0.5, 1, 1, 0.5, 1, -1, -0.5, 1, 1, 0.5, 1, 1, -0.5, 1, -1, -0.5, 1, 1, 0.5, -1, -1, 0.5, -1, 1, -0.5, -1, -1, 0.5, -1, -1, -0.5, -1, 1, -0.5, -1, 1, 0.5, 1, 1, 0.5, -1, 1, -0.5, 1, 1, 0.5, -1, 1, -0.5, -1, 1, -0.5, 1, -1, 0.5, -1, -1, 0.5, 1, -1, -0.5, -1, -1, 0.5, 1, -1, -0.5, 1, -1, -0.5, -1, 1, 0.5, 1, -1, 0.5, 1, 1, 0.5, -1, -1, 0.5, 1, -1, 0.5, -1, 1, 0.5, -1, -1, -0.5, 1, 1, -0.5, 1, -1, -0.5, -1, 1, -0.5, 1, 1, -0.5, -1, -1, -0.5, -1) + +[sub_resource type="MeshLibrary" id="MeshLibrary_jsk3o"] +item/0/name = "Cube" +item/0/mesh = SubResource("BoxMesh_a202f") +item/0/mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) +item/0/mesh_cast_shadow = 1 +item/0/shapes = [SubResource("ConcavePolygonShape3D_7h0kd"), Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)] +item/0/navigation_mesh = SubResource("NavigationMesh_qra7f") +item/0/navigation_mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) +item/0/navigation_layers = 1 +item/0/preview = SubResource("ImageTexture_a0tk4") +metadata/_editor_source_scene = "res://tiles.tscn" + +[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_4arys"] + +[sub_resource type="FogMaterial" id="FogMaterial_6iypd"] +density = -1.0 +edge_fade = 1e-05 + +[sub_resource type="PathExtrudeProfileRect" id="PathExtrudeProfileRect_noarx"] +rect = Rect2(0, 0, 1, 0.25) + +[sub_resource type="Curve3D" id="Curve3D_a0tk4"] +closed = true +_data = { +"points": PackedVector3Array(-1.5895, 0.547675, -1.2548, 1.5895, -0.547675, 1.2548, 7.58029, -1.96974, 2.38484, 0.622387, 0.958949, -2.33984, -0.622387, -0.958949, 2.33984, 10.4758, -3.60798, 7.74932, 1.00351, -0.0737343, -1.08957, -1.00351, 0.0737343, 1.08957, 8.90853, -3.95691, 12.793, 0.940016, -0.323963, -0.0481977, -0.940016, 0.323963, 0.0481977, 4.82363, -3.71584, 14.2897, 0.754678, -0.502582, 0.404814, -0.754678, 0.502582, -0.404814, 2.14693, -2.76914, 13.5782, 0.402288, -0.897991, 0.986384, -0.402288, 0.897991, -0.986384, 0.731074, -1.86138, 11.2657, 0.470512, -0.16093, 0.925209, -0.470512, 0.16093, -0.925209, -0.10452, -0.530769, 8.39589, -0.930698, -0.0675459, 1.18981, 0.930698, 0.0675459, -1.18981, 0.154793, 0.10254, 4.75157, -1.98598, 0.304792, 1.01842, 1.98598, -0.304792, -1.01842, 2.71024, -0.225047, 1.74686), +"tilts": PackedFloat32Array(0, 0, 0, 0, 0, 0, 0, 0, 0) +} +point_count = 9 + +[sub_resource type="Curve3D" id="Curve3D_r3fl7"] +closed = true +_data = { +"points": PackedVector3Array(-1.5895, 0.547675, -1.2548, 1.5895, -0.547675, 1.2548, 7.58029, -1.96974, 2.38484, 0.622387, 0.958949, -2.33984, -0.622387, -0.958949, 2.33984, 10.4758, -3.60798, 7.74932, 1.00351, -0.0737343, -1.08957, -1.00351, 0.0737343, 1.08957, 8.90853, -3.95691, 12.793, 0.940016, -0.323963, -0.0481977, -0.940016, 0.323963, 0.0481977, 4.82363, -3.71584, 14.2897, 0.754678, -0.502582, 0.404814, -0.754678, 0.502582, -0.404814, 2.14693, -2.76914, 13.5782, 0.402288, -0.897991, 0.986384, -0.402288, 0.897991, -0.986384, 0.731074, -1.86138, 11.2657, 0.470512, -0.16093, 0.925209, -0.470512, 0.16093, -0.925209, -0.10452, -0.530769, 8.39589, -0.930698, -0.0675459, 1.18981, 0.930698, 0.0675459, -1.18981, 0.154793, 0.10254, 4.75157, -1.98598, 0.304792, 1.01842, 1.98598, -0.304792, -1.01842, 2.71024, -0.225047, 1.74686), +"tilts": PackedFloat32Array(0, 0, 0, 0, 0, 0, 0, 0, 0) +} +point_count = 9 + +[node name="Node3D" type="Node3D"] + +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = SubResource("Environment_noarx") +camera_attributes = SubResource("CameraAttributesPractical_a0tk4") + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] +transform = Transform3D(-0.866025, -0.433013, 0.25, -0.116689, 0.661226, 0.741056, -0.486193, 0.612601, -0.623166, 0, 0, 0) +shadow_enabled = true + +[node name="GridMap" type="GridMap" parent="."] +mesh_library = SubResource("MeshLibrary_jsk3o") +physics_material = SubResource("PhysicsMaterial_4arys") +cell_size = Vector3(2, 1, 2) +bake_navigation = true +data = { +"cells": PackedInt32Array(0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0, 0, 9, 0, 0, 10, 0, 1, 0, 0, 1, 1, 0, 1, 2, 0, 1, 3, 0, 1, 4, 0, 1, 5, 0, 1, 6, 0, 1, 7, 0, 1, 8, 0, 1, 9, 0, 1, 10, 0, 2, 0, 0, 2, 1, 0, 2, 2, 0, 2, 3, 0, 2, 4, 0, 2, 5, 0, 2, 6, 0, 2, 7, 0, 2, 8, 0, 2, 9, 0, 2, 10, 0, 3, 0, 0, 3, 1, 0, 3, 2, 0, 3, 3, 0, 3, 4, 0, 3, 5, 0, 3, 6, 0, 3, 7, 0, 3, 8, 0, 3, 9, 0, 3, 10, 0, 4, 0, 0, 4, 1, 0, 4, 2, 0, 4, 3, 0, 4, 4, 0, 4, 5, 0, 4, 6, 0, 4, 7, 0, 4, 8, 0, 4, 9, 0, 4, 10, 0, 5, 0, 0, 5, 1, 0, 5, 2, 0, 5, 3, 0, 5, 4, 0, 5, 5, 0, 5, 6, 0, 5, 7, 0, 5, 8, 0, 5, 9, 0, 5, 10, 0, 6, 0, 0, 6, 1, 0, 6, 2, 0, 6, 3, 0, 6, 4, 0, 6, 5, 0, 6, 6, 0, 6, 7, 0, 6, 8, 0, 6, 9, 0, 6, 10, 0, 7, 0, 0, 7, 1, 0, 7, 2, 0, 7, 3, 0, 7, 4, 0, 7, 5, 0, 7, 6, 0, 7, 7, 0, 7, 8, 0, 7, 9, 0, 7, 10, 0, 8, 0, 0, 8, 1, 0, 8, 2, 0, 8, 3, 0, 8, 4, 0, 8, 5, 0, 8, 6, 0, 8, 7, 0, 8, 8, 0, 8, 9, 0, 8, 10, 0, 9, 0, 0, 9, 1, 0, 9, 2, 0, 9, 3, 0, 9, 4, 0, 9, 5, 0, 9, 6, 0, 9, 7, 0, 9, 8, 0, 9, 9, 0, 9, 10, 0, 10, 0, 0, 10, 1, 0, 10, 2, 0, 10, 3, 0, 10, 4, 0, 10, 5, 0, 10, 6, 0, 10, 7, 0, 10, 8, 0, 10, 9, 0, 10, 10, 0, 11, 0, 0, 11, 1, 0, 11, 2, 0, 11, 3, 0, 11, 4, 0, 11, 5, 0, 11, 6, 0, 11, 7, 0, 11, 8, 0, 11, 9, 0, 11, 10, 0) +} +script = ExtResource("1_noarx") +metadata/_editor_floor_ = Vector3(0, 4, 0) + +[node name="PathfindingGrid" type="Node3D" parent="GridMap"] +script = ExtResource("2_noarx") + +[node name="StaticBody3D" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 9.09688, 0.844006, 10.3542) + +[node name="Camera3D" type="Camera3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 10.1975, 10, 19.2994) +doppler_tracking = 2 +current = true + +[node name="FogVolume" type="FogVolume" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.962624, 11.8561, 3.93469) +visible = false +size = Vector3(53.7622, 43.4556, 41.8376) +material = SubResource("FogMaterial_6iypd") + +[node name="OmniLight3D" type="OmniLight3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4, -3) +omni_range = 12.0 + +[node name="PathExtrude3D" type="PathExtrude3D" parent="." node_paths=PackedStringArray("path_3d")] +path_3d = NodePath("Path3D") +profile = SubResource("PathExtrudeProfileRect_noarx") +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4.80993, 13.2424, -10.834) + +[node name="Path3D" type="Path3D" parent="PathExtrude3D"] +curve = SubResource("Curve3D_a0tk4") + +[node name="PathMesh3D" type="PathMesh3D" parent="." node_paths=PackedStringArray("path_3d")] +path_3d = NodePath("Path3D2") +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 9.33173, 0, 4.85746) + +[node name="Path3D2" type="Path3D" parent="PathMesh3D"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 30.6883, 12.084, -12.8564) +curve = SubResource("Curve3D_r3fl7") diff --git a/pathfinding_grid.gd b/pathfinding_grid.gd new file mode 100644 index 0000000..58cb54a --- /dev/null +++ b/pathfinding_grid.gd @@ -0,0 +1,79 @@ +@tool +extends Node3D + +@export var cell_grid_size: int = 1 +@export var offset: Vector3 = Vector3(-1, 1, -1) + +var astar_grid: AStar3D = AStar3D.new() +var timer: float = 0 + +func _ready() -> void: + get_parent().connect("map_changed", generate) + +func _process(delta: float) -> void: + pass + #timer += delta + #if timer >= 1: + #timer = 0 + ##timer -= 1 + #generate() + +func generate() -> void: + astar_grid.clear() + + var cell_cast_positions: Array[Vector3] = get_cell_cast_positions() + + var next_point_id: int = 0 + var point_id_map: Dictionary[Vector3i, int] + + for cell in get_parent().get_used_cells(): + if get_parent().get_cell_item(cell + Vector3i(0,1,0)) != GridMap.INVALID_CELL_ITEM: + continue # skip cells that are covered by something + + for cast_position in cell_cast_positions: + var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.new() + params.from = cast_position + get_parent().map_to_local(cell) + params.to = params.from + Vector3.DOWN * 2 + params.collision_mask = get_parent().collision_layer + #print("Raycasting from %s to %s" % [params.from, params.to]) + DebugDraw3D.draw_line(params.from, params.to, Color.RED, 1) + var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params) + if result.has("position"): + var path_point: Vector3 = result["position"] + offset + DebugDraw3D.draw_sphere(path_point, 0.5, Color.YELLOW, 1) + astar_grid.add_point(next_point_id, path_point, 1.0) + point_id_map[cell] = next_point_id + next_point_id += 1 + + for cell in point_id_map.keys(): + var point_id: int = point_id_map[cell] + var point_pos: Vector3 = astar_grid.get_point_position(point_id) + for x in range(-1, 2): + for y in range(-1, 2): + for z in range(-1, 2): + var neighbour_cell: Vector3i = cell + Vector3i(x,y,z) + if point_id_map.has(neighbour_cell): + var neighbour_point_id: int = point_id_map[neighbour_cell] + if astar_grid.are_points_connected(neighbour_point_id, point_id): + continue + var neighbour_point_pos: Vector3 = astar_grid.get_point_position(neighbour_point_id) + var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.new() + params.from = point_pos + params.to = neighbour_point_pos + params.collision_mask = get_parent().collision_layer + var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params) + if !result.has("position"): + astar_grid.connect_points(point_id, neighbour_point_id) + DebugDraw3D.draw_line(params.from, params.to, Color.YELLOW, 1) + + #print(result.keys()) + +func get_cell_cast_positions() -> Array[Vector3]: + var ret: Array[Vector3] = [] + var frac: int = cell_grid_size * 2 + for x in range(1, frac, 2): + var x_pos: float = (x / float(frac)) * get_parent().cell_size.x + for y in range(1, frac, 2): + var y_pos: float = (y / float(frac)) * get_parent().cell_size.z + ret.append(Vector3(x_pos, 1, y_pos)) + return ret diff --git a/pathfinding_grid.gd.uid b/pathfinding_grid.gd.uid new file mode 100644 index 0000000..b3e6080 --- /dev/null +++ b/pathfinding_grid.gd.uid @@ -0,0 +1 @@ +uid://ghsl3wni57q1 diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..45d0039 --- /dev/null +++ b/project.godot @@ -0,0 +1,37 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="TowerGame3D" +run/main_scene="uid://bwftban1ppo17" +config/features=PackedStringArray("4.4") +config/icon="res://icon.svg" + +[editor] + +version_control/plugin_name="GitPlugin" +version_control/autoload_on_startup=true + +[editor_plugins] + +enabled=PackedStringArray("res://addons/PathMesh3D/plugin.cfg", "res://addons/git_describe/plugin.cfg") + +[navigation] + +3d/default_edge_connection_margin=1.5 + +[rendering] + +lights_and_shadows/directional_shadow/soft_shadow_filter_quality=0 +lights_and_shadows/positional_shadow/soft_shadow_filter_quality=0 +anti_aliasing/quality/msaa_2d=1 +anti_aliasing/quality/msaa_3d=1 +anti_aliasing/quality/screen_space_aa=1 diff --git a/tiles.tscn b/tiles.tscn new file mode 100644 index 0000000..9efc593 --- /dev/null +++ b/tiles.tscn @@ -0,0 +1,36 @@ +[gd_scene load_steps=5 format=3 uid="uid://bexxobgiojrfa"] + +[sub_resource type="BoxMesh" id="BoxMesh_qra7f"] +size = Vector3(2, 1, 2) + +[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_7h0kd"] +data = PackedVector3Array(-1, 0.5, 1, 1, 0.5, 1, -1, -0.5, 1, 1, 0.5, 1, 1, -0.5, 1, -1, -0.5, 1, 1, 0.5, -1, -1, 0.5, -1, 1, -0.5, -1, -1, 0.5, -1, -1, -0.5, -1, 1, -0.5, -1, 1, 0.5, 1, 1, 0.5, -1, 1, -0.5, 1, 1, 0.5, -1, 1, -0.5, -1, 1, -0.5, 1, -1, 0.5, -1, -1, 0.5, 1, -1, -0.5, -1, -1, 0.5, 1, -1, -0.5, 1, -1, -0.5, -1, 1, 0.5, 1, -1, 0.5, 1, 1, 0.5, -1, -1, 0.5, 1, -1, 0.5, -1, 1, 0.5, -1, -1, -0.5, 1, 1, -0.5, 1, -1, -0.5, -1, 1, -0.5, 1, 1, -0.5, -1, -1, -0.5, -1) + +[sub_resource type="NavigationMesh" id="NavigationMesh_qra7f"] +vertices = PackedVector3Array(-0.75, 1, -0.75, -0.75, 1, 0.75, 0.75, 1, 0.75, 0.75, 1, -0.75) +polygons = [PackedInt32Array(3, 2, 0), PackedInt32Array(0, 2, 1)] +sample_partition_type = 2 +agent_radius = 0.2 +region_min_size = 1.0 +filter_walkable_low_height_spans = true + +[sub_resource type="QuadMesh" id="QuadMesh_7h0kd"] +size = Vector2(2, 2) +center_offset = Vector3(0, 0.5, 0) +orientation = 1 + +[node name="Tiles" type="Node3D"] + +[node name="Cube" type="MeshInstance3D" parent="."] +mesh = SubResource("BoxMesh_qra7f") + +[node name="StaticBody3D" type="StaticBody3D" parent="Cube"] + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Cube/StaticBody3D"] +shape = SubResource("ConcavePolygonShape3D_7h0kd") + +[node name="NavigationRegion3D" type="NavigationRegion3D" parent="Cube"] +navigation_mesh = SubResource("NavigationMesh_qra7f") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Cube/NavigationRegion3D"] +mesh = SubResource("QuadMesh_7h0kd")