diff --git a/hexmapper/.editorconfig b/hexmapper/.editorconfig new file mode 100644 index 0000000..f28239b --- /dev/null +++ b/hexmapper/.editorconfig @@ -0,0 +1,4 @@ +root = true + +[*] +charset = utf-8 diff --git a/hexmapper/Testscene.tscn b/hexmapper/Testscene.tscn new file mode 100644 index 0000000..9b3bd2e --- /dev/null +++ b/hexmapper/Testscene.tscn @@ -0,0 +1,64 @@ +[gd_scene load_steps=7 format=3 uid="uid://hlrngp1n24kg"] + +[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_gbjqf"] +load_path = "res://.godot/imported/BoulderHills1.png-3ee92d43833962adc5c138e74c73b76b.ctex" + +[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_ioj5u"] +load_path = "res://.godot/imported/BoulderHills1.png-3ee92d43833962adc5c138e74c73b76b.ctex" + +[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_g5b6y"] + +[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_slrw0"] +load_path = "res://.godot/imported/Grass1.png-95db52ec56c98c7586df38eac38ccfca.ctex" + +[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_af0e7"] +load_path = "res://.godot/imported/Grass2.png-d618be34b2012c09fbdb1c5ef19013bf.ctex" + +[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_8oe3q"] +load_path = "res://.godot/imported/Grass3.png-f00b17931a597c8e0f903ee630d4c100.ctex" + +[node name="Node2D" type="Node2D"] + +[node name="BoulderHills1" type="Sprite2D" parent="."] +position = Vector2(487, 413) +texture = SubResource("CompressedTexture2D_gbjqf") + +[node name="BoulderHills1" type="Sprite2D" parent="BoulderHills1"] +position = Vector2(474, 412) +texture = SubResource("CompressedTexture2D_gbjqf") + +[node name="BoulderHills2" type="Sprite2D" parent="."] +position = Vector2(540, 448) +texture = SubResource("CompressedTexture2D_gbjqf") + +[node name="BoulderHills3" type="Sprite2D" parent="."] +position = Vector2(434, 449) +texture = SubResource("CompressedTexture2D_gbjqf") + +[node name="BoulderHills4" type="Sprite2D" parent="."] +position = Vector2(487, 484) +texture = SubResource("CompressedTexture2D_gbjqf") + +[node name="Brambles1" type="Sprite2D" parent="."] +position = Vector2(540, 377) +texture = SubResource("CompressedTexture2D_ioj5u") + +[node name="Church5" type="Sprite2D" parent="."] +position = Vector2(432, 381) +texture = SubResource("CompressedTexture2D_g5b6y") + +[node name="Grass1" type="Sprite2D" parent="."] +position = Vector2(485, 343) +texture = SubResource("CompressedTexture2D_slrw0") + +[node name="Grass2" type="Sprite2D" parent="."] +position = Vector2(430, 309) +texture = SubResource("CompressedTexture2D_af0e7") + +[node name="Grass3" type="Sprite2D" parent="."] +position = Vector2(377, 346) +texture = SubResource("CompressedTexture2D_8oe3q") + +[node name="Grass4" type="Sprite2D" parent="."] +position = Vector2(379, 418) +texture = SubResource("CompressedTexture2D_8oe3q") diff --git a/hexmapper/_autoload/global.gd b/hexmapper/_autoload/global.gd new file mode 100644 index 0000000..fe8d287 --- /dev/null +++ b/hexmapper/_autoload/global.gd @@ -0,0 +1,3 @@ +extends Node + +@export var settings:Settings = Settings.new() diff --git a/hexmapper/_autoload/global.gd.uid b/hexmapper/_autoload/global.gd.uid new file mode 100644 index 0000000..6f91c8f --- /dev/null +++ b/hexmapper/_autoload/global.gd.uid @@ -0,0 +1 @@ +uid://dd76wxdxcm1v0 diff --git a/hexmapper/addons/AsepriteWizard/aseprite/aseprite.gd b/hexmapper/addons/AsepriteWizard/aseprite/aseprite.gd new file mode 100644 index 0000000..d7137a6 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/aseprite/aseprite.gd @@ -0,0 +1,306 @@ +@tool +extends RefCounted + +var _config = preload("../config/config.gd").new() + +# +# Output: +# { +# "data_file": file path to the json file +# "sprite_sheet": file path to the raw image file +# } +func export_file(file_name: String, output_folder: String, options: Dictionary) -> Dictionary: + var exception_pattern = options.get('exception_pattern', "") + var only_visible_layers = options.get('only_visible_layers', false) + var output_name = file_name if options.get('output_filename') == "" else options.get('output_filename', file_name) + var first_frame_only = options.get("first_frame_only", false) + var basename = _get_file_basename(output_name) + var output_dir = ProjectSettings.globalize_path(output_folder) + var data_file = "%s/%s.json" % [output_dir, basename] + var sprite_sheet = "%s/%s.png" % [output_dir, basename] + var output = [] + var arguments = _export_command_common_arguments(file_name, data_file, sprite_sheet) + + if not only_visible_layers: + arguments.push_front("--all-layers") + + if first_frame_only: + arguments.push_front("'[0, 0]'") + arguments.push_front("--frame-range") + + _add_sheet_type_arguments(arguments, options) + + _add_ignore_layer_arguments(file_name, arguments, exception_pattern) + + var local_sprite_sheet_path = ProjectSettings.localize_path(sprite_sheet) + var is_new = not ResourceLoader.exists(local_sprite_sheet_path) + + var exit_code = _execute(arguments, output) + if exit_code != 0: + printerr('aseprite: failed to export spritesheet') + printerr(output) + return {} + + return { + "data_file": ProjectSettings.localize_path(data_file), + "sprite_sheet": local_sprite_sheet_path, + "is_first_import": is_new, + } + + +func export_layers(file_name: String, output_folder: String, options: Dictionary) -> Array: + var exception_pattern = options.get('exception_pattern', "") + var only_visible_layers = options.get('only_visible_layers', false) + var basename = _get_file_basename(file_name) + var layers = list_layers(file_name, only_visible_layers) + var exception_regex = _compile_regex(exception_pattern) + + var output = [] + + for layer in layers: + if layer != "" and (not exception_regex or exception_regex.search(layer) == null): + output.push_back(export_file_with_layers(file_name, [layer], output_folder, options)) + + return output + + +func export_file_with_layers(file_name: String, layer_names: Array, output_folder: String, options: Dictionary) -> Dictionary: + var output_prefix = options.get('output_filename', "").strip_edges() + var output_dir = output_folder.replace("res://", "./").strip_edges() + var base_output_path = "%s/%s%s" % [output_dir, output_prefix, layer_names[0] if layer_names.size() == 1 else ""] + var data_file = "%s.json" % base_output_path + var sprite_sheet = "%s.png" % base_output_path + var first_frame_only = options.get("first_frame_only", false) + var output = [] + var arguments = _export_command_common_arguments(file_name, data_file, sprite_sheet) + + for layer_name in layer_names: + arguments.push_front(layer_name) + arguments.push_front("--layer") + + if first_frame_only: + arguments.push_front("'[0, 0]'") + arguments.push_front("--frame-range") + + _add_sheet_type_arguments(arguments, options) + + var local_sprite_sheet_path = ProjectSettings.localize_path(sprite_sheet) + var is_new = not ResourceLoader.exists(local_sprite_sheet_path) + + var exit_code = _execute(arguments, output) + if exit_code != 0: + print('aseprite: failed to export layer spritesheet') + print(output) + return {} + + return { + "data_file": ProjectSettings.localize_path(data_file), + "sprite_sheet": local_sprite_sheet_path, + "is_first_import": is_new, + } + + +func _add_ignore_layer_arguments(file_name: String, arguments: Array, exception_pattern: String): + var layers = _get_exception_layers(file_name, exception_pattern) + if not layers.is_empty(): + for l in layers: + arguments.push_front(l) + arguments.push_front('--ignore-layer') + + +func _add_sheet_type_arguments(arguments: Array, options : Dictionary): + var sheet_type = options.get("sheet_type", "packed") + var item_count = options.get("sheet_columns", 0) + + if (sheet_type == "columns" or sheet_type == "rows") and item_count == 0: + sheet_type = "packed" + elif options.get("sheet_merge_duplicates", true): + arguments.push_back("--merge-duplicates") + + if sheet_type == "columns": + arguments.push_back("--sheet-columns") + arguments.push_back(item_count) + else: + arguments.push_back("--sheet-type") + arguments.push_back(sheet_type) + + +func _get_exception_layers(file_name: String, exception_pattern: String) -> Array: + var layers = list_layers(file_name) + var regex = _compile_regex(exception_pattern) + if regex == null: + return [] + + var exception_layers = [] + for layer in layers: + if regex.search(layer) != null: + exception_layers.push_back(layer) + + return exception_layers + + +func list_valid_layers(file_name: String, exception_pattern: String = "", show_only_visible: bool = false) -> Array: + var layers = list_layers(file_name, show_only_visible) + var exception_regex = _compile_regex(exception_pattern) + + var output = [] + + for layer in layers: + if layer != "" and (not exception_regex or exception_regex.search(layer) == null): + output.push_back(layer) + + return output + + +func list_layers(file_name: String, only_visible = false) -> Array: + var output = [] + var arguments = ["-b", "--list-layers", file_name] + + if not only_visible: + arguments.push_front("--all-layers") + + var exit_code = _execute(arguments, output) + + if exit_code != 0: + printerr('aseprite: failed listing layers') + printerr(output) + return [] + + if output.is_empty(): + return output + + var raw = output[0].split('\n') + var sanitized = [] + for s in raw: + sanitized.append(s.strip_edges()) + return sanitized + + +func list_slices(file_name: String) -> Array: + var output = [] + var arguments = ["-b", "--list-slices", file_name] + + var exit_code = _execute(arguments, output) + + if exit_code != 0: + printerr('aseprite: failed listing slices') + printerr(output) + return [] + + if output.is_empty(): + return output + + var raw = output[0].split('\n') + var sanitized = [] + for s in raw: + sanitized.append(s.strip_edges()) + return sanitized + + +func _export_command_common_arguments(source_name: String, data_path: String, spritesheet_path: String) -> Array: + return [ + "-b", + "--list-tags", + "--list-slices", + "--data", + data_path, + "--format", + "json-array", + "--sheet", + spritesheet_path, + source_name + ] + + +func _execute(arguments, output): + return OS.execute(_aseprite_command(), arguments, output, true, true) + + +func _aseprite_command() -> String: + return _config.is_command_or_control_pressed() + + +func _get_file_basename(file_path: String) -> String: + return file_path.get_file().trim_suffix('.%s' % file_path.get_extension()) + + +func _compile_regex(pattern): + if pattern == "": + return + + var rgx = RegEx.new() + if rgx.compile(pattern) == OK: + return rgx + + printerr('exception regex error') + + +func test_command(): + var exit_code = OS.execute(_aseprite_command(), ['--version'], [], true) + return exit_code == 0 + + +func is_valid_spritesheet(content): + return content.has("frames") and content.has("meta") and content.meta.has('image') + + +func get_content_frames(content): + return content.frames if typeof(content.frames) == TYPE_ARRAY else content.frames.values() + + +func get_slice_rect(content: Dictionary, slice_name: String) -> Variant: + if not content.has("meta") or not content.meta.has("slices"): + return null + for slice in content.meta.slices: + if slice.name == slice_name: + if slice.keys.size() > 0: + var p = slice.keys[0].bounds + return Rect2(p.x, p.y, p.w, p.h) + return null + + +## +## Exports tileset layers +## +## Return (dictionary): +## data_file: path to aseprite generated JSON file +## sprite_sheet: localized path to spritesheet file +func export_tileset_texture(file_name: String, output_folder: String, options: Dictionary) -> Dictionary: + var exception_pattern = options.get('exception_pattern', "") + var only_visible_layers = options.get('only_visible_layers', false) + var output_name = file_name if options.get('output_filename') == "" else options.get('output_filename', file_name) + var basename = _get_file_basename(output_name) + var output_dir = ProjectSettings.globalize_path(output_folder) + var data_path = "%s/%s.json" % [output_dir, basename] + var sprite_sheet = "%s/%s.png" % [output_dir, basename] + var output = [] + + var arguments = [ + "-b", + "--export-tileset", + "--data", + data_path, + "--format", + "json-array", + "--sheet", + sprite_sheet, + file_name + ] + + if not only_visible_layers: + arguments.push_front("--all-layers") + + _add_sheet_type_arguments(arguments, options) + + _add_ignore_layer_arguments(file_name, arguments, exception_pattern) + + var exit_code = _execute(arguments, output) + if exit_code != 0: + printerr('aseprite: failed to export spritesheet') + printerr(output) + return {} + + return { + "data_file": ProjectSettings.localize_path(data_path), + "sprite_sheet": ProjectSettings.localize_path(sprite_sheet) + } diff --git a/hexmapper/addons/AsepriteWizard/aseprite/aseprite.gd.uid b/hexmapper/addons/AsepriteWizard/aseprite/aseprite.gd.uid new file mode 100644 index 0000000..3c20d13 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/aseprite/aseprite.gd.uid @@ -0,0 +1 @@ +uid://dlagp0c0t7o6x diff --git a/hexmapper/addons/AsepriteWizard/aseprite/file_exporter.gd b/hexmapper/addons/AsepriteWizard/aseprite/file_exporter.gd new file mode 100644 index 0000000..e290608 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/aseprite/file_exporter.gd @@ -0,0 +1,146 @@ +@tool +extends RefCounted + +var result_code = preload("../config/result_codes.gd") +var _aseprite = preload("aseprite.gd").new() + +enum { + FILE_EXPORT_MODE, + LAYERS_EXPORT_MODE +} + +## +## Generate Aseprite spritesheet and data files for source. +## +## Options: +## output_folder (string) +## output_filename (string, optional) +## export_mode (FILE_EXPORT_MODE, LAYERS_EXPORT_MODE) default: FILE_EXPORT_MODE +## exception_pattern (string, optional) +## only_visible_layers (boolean, optional) +## +## Return: +## Array +## Dictionary +## sprite_sheet: sprite sheet path +## data_file: json file path +## +func generate_aseprite_files(source_file: String, options: Dictionary): + var check = _initial_checks(source_file, options) + + if check != result_code.SUCCESS: + return result_code.error(check) + + match options.get('export_mode', FILE_EXPORT_MODE): + FILE_EXPORT_MODE: + var output = _aseprite.export_file(source_file, options.output_folder, options) + if output.is_empty(): + return result_code.error(result_code.ERR_ASEPRITE_EXPORT_FAILED) + return result_code.result([output]) + LAYERS_EXPORT_MODE: + var output = _aseprite.export_layers(source_file, options.output_folder, options) + if output.is_empty(): + return result_code.error(result_code.ERR_NO_VALID_LAYERS_FOUND) + return result_code.result(output) + _: + return result_code.error(result_code.ERR_UNKNOWN_EXPORT_MODE) + + +## +## Generate Aseprite spritesheet and data file for source. +## +## Options: +## output_folder (string) +## output_filename (string, optional) +## layer (string, optional) +## exception_pattern (string, optional) +## only_visible_layers (boolean, optional) +## +## Return: +## Dictionary +## sprite_sheet: sprite sheet path +## data_file: json file path +## +func generate_aseprite_file(source_file: String, options: Dictionary) -> Dictionary: + var check = _initial_checks(source_file, options) + + if check != result_code.SUCCESS: + return result_code.error(check) + + var output + + if options.get("layer") != null and options.get("layer") != "": + output = _aseprite.export_file_with_layers(source_file, [options.layer], options.output_folder, options) + elif options.get("layers", []).size() > 0: + output = _aseprite.export_file_with_layers(source_file, options.layers, options.output_folder, options) + else: + output = _aseprite.export_file(source_file, options.output_folder, options) + + + if output.is_empty(): + return result_code.error(result_code.ERR_ASEPRITE_EXPORT_FAILED) + + return result_code.result(output) + + +## +## Generate a spritesheet with all tilesets in the file +## +## Options: +## exception_pattern (string) +## only_visible_layers (boolean) +## output_filename (string) +## output_folder (string) +## +## Return: +## Dictionary +## sprite_sheet: sprite sheet path +## data_file: json file path +## +func generate_tileset_files(source_file: String, options = {}) -> Dictionary: + var check = _initial_checks(source_file, options) + + if check != result_code.SUCCESS: + return result_code.error(check) + + var output = _aseprite.export_tileset_texture(source_file, options.output_folder, options) + + if output.is_empty(): + return result_code.error(result_code.ERR_ASEPRITE_EXPORT_FAILED) + + return result_code.result(output) + + +## +## Perform initial source file and output folder checks +## +func _initial_checks(source: String, options: Dictionary) -> int: + if not _aseprite.test_command(): + return result_code.ERR_ASEPRITE_CMD_NOT_FOUND + + if not FileAccess.file_exists(source): + return result_code.ERR_SOURCE_FILE_NOT_FOUND + + if not DirAccess.dir_exists_absolute(options.output_folder): + return result_code.ERR_OUTPUT_FOLDER_NOT_FOUND + + return result_code.SUCCESS + + +## +## Load Aseprite source data file and fails if the +## content is not valid +## +func load_json_content(source_file: String) -> Dictionary: + var file = FileAccess.open(source_file, FileAccess.READ) + if file == null: + return result_code.error(FileAccess.get_open_error()) + var test_json_conv = JSON.new() + test_json_conv.parse(file.get_as_text()) + + var content = test_json_conv.get_data() + + if not _aseprite.is_valid_spritesheet(content): + return result_code.error(result_code.ERR_INVALID_ASEPRITE_SPRITESHEET) + + return result_code.result(content) diff --git a/hexmapper/addons/AsepriteWizard/aseprite/file_exporter.gd.uid b/hexmapper/addons/AsepriteWizard/aseprite/file_exporter.gd.uid new file mode 100644 index 0000000..1e46ba3 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/aseprite/file_exporter.gd.uid @@ -0,0 +1 @@ +uid://cqqxrajqhsbix diff --git a/hexmapper/addons/AsepriteWizard/config/config.gd b/hexmapper/addons/AsepriteWizard/config/config.gd new file mode 100644 index 0000000..a624657 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/config/config.gd @@ -0,0 +1,212 @@ +@tool +extends RefCounted + +# GLOBAL SETTINGS +const _CONFIG_SECTION_KEY = 'aseprite' +const _COMMAND_KEY = 'aseprite/general/command_path' + +# PROJECT SETTINGS + +# animation import defaults +const _DEFAULT_EXCLUSION_PATTERN_KEY = 'aseprite/animation/layers/exclusion_pattern' +const _DEFAULT_ONLY_VISIBLE_LAYERS = 'aseprite/animation/layers/only_include_visible_layers_by_default' +const _DEFAULT_LOOP_EX_PREFIX = '_' +const _LOOP_ENABLED = 'aseprite/animation/loop/enabled' +const _LOOP_EXCEPTION_PREFIX = 'aseprite/animation/loop/exception_prefix' + +# cleanup +const _REMOVE_SOURCE_FILES_KEY = 'aseprite/import/cleanup/remove_json_file' +const _SET_VISIBLE_TRACK_AUTOMATICALLY = 'aseprite/import/cleanup/automatically_hide_sprites_not_in_animation' + +# automatic importer +const _IMPORTER_ENABLE_KEY = 'aseprite/import/import_plugin/enable_automatic_importer' +const _DEFAULT_IMPORTER_KEY = 'aseprite/import/import_plugin/default_automatic_importer' + +const IMPORTER_SPRITEFRAMES_NAME = "SpriteFrames" +const IMPORTER_SPRITEFRAMES_SPLIT_NAME = "SpriteFrames (Split By Layer)" +const IMPORTER_NOOP_NAME = "No Import" +const IMPORTER_TILESET_TEXTURE_NAME = "Tileset Texture" +const IMPORTER_STATIC_TEXTURE_NAME = "Static Texture" +const IMPORTER_STATIC_TEXTURE_SPLIT_NAME = "Static Texture (Split By Layer)" + +# wizard history +const _WIZARD_HISTORY = "wizard_history" +const _HISTORY_MAX_ENTRIES = 'aseprite/wizard/history/max_history_entries' +const _HISTORY_DEFAULT_MAX_ENTRIES = 100 + +# SpriteFrames import last config +const _STANDALONE_SPRITEFRAMES_LAST_IMPORT_CFG = "standalone_sf_last_import_cfg" + +var _editor_settings: EditorSettings = EditorInterface.get_editor_settings() + +####################################################### +# GLOBAL CONFIGS +###################################################### + +func default_command() -> String: + match OS.get_name(): + "Windows": + return "C:\\\\Steam\\steamapps\\common\\Aseprite\\aseprite.exe" + "macOS": + return "/Applications/Aseprite.app/Contents/MacOS/aseprite" + _: + return 'aseprite' + + +func is_command_or_control_pressed() -> String: + var command = _editor_settings.get(_COMMAND_KEY) if _editor_settings.has_setting(_COMMAND_KEY) else "" + return command if command != "" else default_command() + + +####################################################### +# PROJECT SETTINGS +###################################################### + +# remove this config in the next major version +func is_importer_enabled() -> bool: + return _get_project_setting(_IMPORTER_ENABLE_KEY, false) + + +func get_default_importer() -> String: + return _get_project_setting(_DEFAULT_IMPORTER_KEY, IMPORTER_SPRITEFRAMES_NAME if is_importer_enabled() else IMPORTER_NOOP_NAME) + + +func should_remove_source_files() -> bool: + return _get_project_setting(_REMOVE_SOURCE_FILES_KEY, true) + + +func is_default_animation_loop_enabled() -> bool: + return _get_project_setting(_LOOP_ENABLED, true) + + +func get_animation_loop_exception_prefix() -> String: + return _get_project_setting(_LOOP_EXCEPTION_PREFIX, _DEFAULT_LOOP_EX_PREFIX) + + +func get_default_exclusion_pattern() -> String: + return _get_project_setting(_DEFAULT_EXCLUSION_PATTERN_KEY, "") + + +func should_include_only_visible_layers_by_default() -> bool: + return _get_project_setting(_DEFAULT_ONLY_VISIBLE_LAYERS, false) + + +func get_history_max_entries() -> int: + return _get_project_setting(_HISTORY_MAX_ENTRIES, _HISTORY_DEFAULT_MAX_ENTRIES) + + +func get_import_history() -> Array: + return get_plugin_metadata(_WIZARD_HISTORY, []) + + +func is_set_visible_track_automatically_enabled() -> bool: + return _get_project_setting(_SET_VISIBLE_TRACK_AUTOMATICALLY, false) + + +func save_import_history(history: Array): + set_plugin_metadata(_WIZARD_HISTORY, history) + + +#========================================================= +# IMPORT CONFIGS +#========================================================= +## Return config for last import done via standalone SpriteFrames import dock +func get_standalone_spriteframes_last_import_config() -> Dictionary: + return get_plugin_metadata(_STANDALONE_SPRITEFRAMES_LAST_IMPORT_CFG, {}) + +## Set config for last import done via standalone SpriteFrames import dock +func set_standalone_spriteframes_last_import_config(data: Dictionary) -> void: + set_plugin_metadata(_STANDALONE_SPRITEFRAMES_LAST_IMPORT_CFG, data) + + +func clear_standalone_spriteframes_last_import_config() -> void: + set_plugin_metadata(_STANDALONE_SPRITEFRAMES_LAST_IMPORT_CFG, {}) + + +func get_plugin_metadata(key: String, default: Variant = null) -> Variant: + return _editor_settings.get_project_metadata(_CONFIG_SECTION_KEY, key, default) + + +func set_plugin_metadata(key: String, data: Variant): + _editor_settings.set_project_metadata(_CONFIG_SECTION_KEY, key, data) + + +####################################################### +# INITIALIZATION +###################################################### +func initialize_project_settings(): + _initialize_project_cfg(_DEFAULT_EXCLUSION_PATTERN_KEY, "", TYPE_STRING) + _initialize_project_cfg(_DEFAULT_ONLY_VISIBLE_LAYERS, false, TYPE_BOOL) + _initialize_project_cfg(_LOOP_ENABLED, true, TYPE_BOOL) + _initialize_project_cfg(_LOOP_EXCEPTION_PREFIX, _DEFAULT_LOOP_EX_PREFIX, TYPE_STRING) + + _initialize_project_cfg(_REMOVE_SOURCE_FILES_KEY, true, TYPE_BOOL) + _initialize_project_cfg( + _DEFAULT_IMPORTER_KEY, + IMPORTER_SPRITEFRAMES_NAME if is_importer_enabled() else IMPORTER_NOOP_NAME, + TYPE_STRING, + PROPERTY_HINT_ENUM, + ",".join([ + IMPORTER_NOOP_NAME, + IMPORTER_SPRITEFRAMES_NAME, + IMPORTER_SPRITEFRAMES_SPLIT_NAME, + IMPORTER_TILESET_TEXTURE_NAME, + IMPORTER_STATIC_TEXTURE_NAME, + IMPORTER_STATIC_TEXTURE_SPLIT_NAME + ]) + ) + + _initialize_project_cfg(_HISTORY_MAX_ENTRIES, _HISTORY_DEFAULT_MAX_ENTRIES, TYPE_INT) + + _initialize_project_cfg(_SET_VISIBLE_TRACK_AUTOMATICALLY, false, TYPE_BOOL) + + ProjectSettings.save() + + _initialize_editor_cfg(_COMMAND_KEY, default_command(), TYPE_STRING) + + +func clear_project_settings(): + var _all_settings = [ + _DEFAULT_EXCLUSION_PATTERN_KEY, + _LOOP_ENABLED, + _LOOP_EXCEPTION_PREFIX, + _REMOVE_SOURCE_FILES_KEY, + _DEFAULT_IMPORTER_KEY, + _HISTORY_MAX_ENTRIES, + _SET_VISIBLE_TRACK_AUTOMATICALLY, + _DEFAULT_ONLY_VISIBLE_LAYERS, + ] + for key in _all_settings: + ProjectSettings.clear(key) + ProjectSettings.save() + + +func _initialize_project_cfg(key: String, default_value, type: int, hint: int = PROPERTY_HINT_NONE, hint_string = null): + if not ProjectSettings.has_setting(key): + ProjectSettings.set(key, default_value) + ProjectSettings.set_initial_value(key, default_value) + ProjectSettings.add_property_info({ + "name": key, + "type": type, + "hint": hint, + "hint_string": hint_string, + }) + + +func _get_project_setting(key: String, default_value): + if not ProjectSettings.has_setting(key): + return default_value + + var p = ProjectSettings.get(key) + return p if p != null else default_value + + +func _initialize_editor_cfg(key: String, default_value, type: int, hint: int = PROPERTY_HINT_NONE): + if not _editor_settings.has_setting(key): + _editor_settings.set(key, default_value) + _editor_settings.set_initial_value(key, default_value, false) + _editor_settings.add_property_info({ + "name": key, + "type": type, + "hint": hint, + }) diff --git a/hexmapper/addons/AsepriteWizard/config/config.gd.uid b/hexmapper/addons/AsepriteWizard/config/config.gd.uid new file mode 100644 index 0000000..5ef9d57 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/config/config.gd.uid @@ -0,0 +1 @@ +uid://brhdsbpp7c56f diff --git a/hexmapper/addons/AsepriteWizard/config/config_dialog.gd b/hexmapper/addons/AsepriteWizard/config/config_dialog.gd new file mode 100644 index 0000000..50431ec --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/config/config_dialog.gd @@ -0,0 +1,29 @@ +@tool +extends PopupPanel + +var _config = preload("./config.gd").new() + +@onready var _aseprite_command_field = $MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer/aseprite_command +@onready var _version_label = $MarginContainer/VBoxContainer/VBoxContainer/version_found + +func _ready(): + _aseprite_command_field.text = _config.is_command_or_control_pressed() + _version_label.modulate.a = 0 + + +func _on_close_button_up(): + self.hide() + + +func _on_test_pressed(): + var output = [] + if _test_command(output): + _version_label.text = "%s found." % "\n".join(PackedStringArray(output)).strip_edges() + else: + _version_label.text = "Command not found." + _version_label.modulate.a = 1 + + +func _test_command(output): + var exit_code = OS.execute(_aseprite_command_field.text, ['--version'], output, true, true) + return exit_code == 0 diff --git a/hexmapper/addons/AsepriteWizard/config/config_dialog.gd.uid b/hexmapper/addons/AsepriteWizard/config/config_dialog.gd.uid new file mode 100644 index 0000000..8cc3632 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/config/config_dialog.gd.uid @@ -0,0 +1 @@ +uid://d1tuygo3j4fru diff --git a/hexmapper/addons/AsepriteWizard/config/config_dialog.tscn b/hexmapper/addons/AsepriteWizard/config/config_dialog.tscn new file mode 100644 index 0000000..56c92f0 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/config/config_dialog.tscn @@ -0,0 +1,80 @@ +[gd_scene load_steps=2 format=3 uid="uid://d0whlywijwa6s"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/config/config_dialog.gd" id="1"] + +[node name="config_dialog" type="PopupPanel"] +title = "Aseprite Wizard Config" +size = Vector2i(624, 236) +visible = true +unresizable = false +borderless = false +min_size = Vector2i(624, 236) +content_scale_mode = 1 +script = ExtResource("1") + +[node name="MarginContainer" type="MarginContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 4.0 +offset_top = 4.0 +offset_right = -532.0 +offset_bottom = -416.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 + +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Label" type="Label" parent="MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "This configuration moved. +- To edit the aseprite command path, go to Editor > Editor Settings > Aseprite. +- To edit project specific settings, go to Project > Project Settings > Aseprite." + +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="Aseprite Command" type="Label" parent="MarginContainer/VBoxContainer/VBoxContainer"] +layout_mode = 2 +tooltip_text = "Define the path for Aseprite command" +mouse_filter = 1 +text = "Aseprite Command Path" + +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer/VBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="aseprite_command" type="LineEdit" parent="MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +editable = false +caret_blink = true + +[node name="test" type="Button" parent="MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Test" + +[node name="version_found" type="Label" parent="MarginContainer/VBoxContainer/VBoxContainer"] +modulate = Color(1, 1, 1, 0) +layout_mode = 2 +size_flags_horizontal = 3 +text = "Aseprite version found" + +[node name="VBoxContainer2" type="HBoxContainer" parent="MarginContainer/VBoxContainer"] +layout_mode = 2 +alignment = 2 + +[node name="close" type="Button" parent="MarginContainer/VBoxContainer/VBoxContainer2"] +layout_mode = 2 +text = "Close" + +[connection signal="pressed" from="MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer/test" to="." method="_on_test_pressed"] +[connection signal="button_up" from="MarginContainer/VBoxContainer/VBoxContainer2/close" to="." method="_on_close_button_up"] diff --git a/hexmapper/addons/AsepriteWizard/config/result_codes.gd b/hexmapper/addons/AsepriteWizard/config/result_codes.gd new file mode 100644 index 0000000..25baff8 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/config/result_codes.gd @@ -0,0 +1,37 @@ +@tool +extends RefCounted + +const SUCCESS = 0 +const ERR_ASEPRITE_CMD_NOT_FOUND = 1 +const ERR_SOURCE_FILE_NOT_FOUND = 2 +const ERR_OUTPUT_FOLDER_NOT_FOUND = 3 +const ERR_ASEPRITE_EXPORT_FAILED = 4 +const ERR_UNKNOWN_EXPORT_MODE = 5 +const ERR_NO_VALID_LAYERS_FOUND = 6 +const ERR_INVALID_ASEPRITE_SPRITESHEET = 7 + + +static func get_error_message(code: int): + match code: + ERR_ASEPRITE_CMD_NOT_FOUND: + return "Aseprite command failed. Please, check if the right command is in your PATH or configured through \"Editor > Editor Settings > Aseprite > General > Command Path\"." + ERR_SOURCE_FILE_NOT_FOUND: + return "source file does not exist" + ERR_OUTPUT_FOLDER_NOT_FOUND: + return "output location does not exist" + ERR_ASEPRITE_EXPORT_FAILED: + return "unable to import file" + ERR_INVALID_ASEPRITE_SPRITESHEET: + return "aseprite generated bad data file" + ERR_NO_VALID_LAYERS_FOUND: + return "no valid layers found" + _: + return "import failed with code %d" % code + + +static func error(error_code: int): + return { "code": error_code, "content": null, "is_ok": false } + + +static func result(result): + return { "code": SUCCESS, "content": result, "is_ok": true } diff --git a/hexmapper/addons/AsepriteWizard/config/result_codes.gd.uid b/hexmapper/addons/AsepriteWizard/config/result_codes.gd.uid new file mode 100644 index 0000000..96857ea --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/config/result_codes.gd.uid @@ -0,0 +1 @@ +uid://blrm6kct24uus diff --git a/hexmapper/addons/AsepriteWizard/config/wizard_config.gd b/hexmapper/addons/AsepriteWizard/config/wizard_config.gd new file mode 100644 index 0000000..411279f --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/config/wizard_config.gd @@ -0,0 +1,41 @@ +@tool +extends RefCounted + +const WIZARD_CONFIG_META_NAME = "_aseprite_wizard_config_" +const WIZARD_INTERFACE_CONFIG_META_NAME = "_aseprite_wizard_interface_config_" +const SOURCE_FILE_HASH_META_NAME = "_aseprite_wizard_source_file_hash_" + + +static func load_config(node: Object): + if node.has_meta(WIZARD_CONFIG_META_NAME): + return node.get_meta(WIZARD_CONFIG_META_NAME) + + return {} + + +static func save_config(node: Object, cfg: Dictionary): + node.set_meta(WIZARD_CONFIG_META_NAME, cfg) + + +static func has_config(node: Object) -> bool: + return node.has_meta(WIZARD_CONFIG_META_NAME) + + +static func load_interface_config(node: Node, default: Dictionary = {}) -> Dictionary: + if node.has_meta(WIZARD_INTERFACE_CONFIG_META_NAME): + return node.get_meta(WIZARD_INTERFACE_CONFIG_META_NAME) + return default + + +static func save_interface_config(node: Node, cfg:Dictionary) -> void: + node.set_meta(WIZARD_INTERFACE_CONFIG_META_NAME, cfg) + + +static func set_source_hash(node: Object, hash: String) -> void: + node.set_meta(SOURCE_FILE_HASH_META_NAME, hash) + + +static func get_source_hash(node: Object) -> String: + if node.has_meta(SOURCE_FILE_HASH_META_NAME): + return node.get_meta(SOURCE_FILE_HASH_META_NAME) + return "" diff --git a/hexmapper/addons/AsepriteWizard/config/wizard_config.gd.uid b/hexmapper/addons/AsepriteWizard/config/wizard_config.gd.uid new file mode 100644 index 0000000..4d4f912 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/config/wizard_config.gd.uid @@ -0,0 +1 @@ +uid://b5c7fprurl46l diff --git a/hexmapper/addons/AsepriteWizard/creators/animation_player/animation_creator.gd b/hexmapper/addons/AsepriteWizard/creators/animation_player/animation_creator.gd new file mode 100644 index 0000000..ed3ab8d --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/creators/animation_player/animation_creator.gd @@ -0,0 +1,338 @@ +@tool +extends "../base_sprite_resource_creator.gd" + +const wizard_config = preload("../../config/wizard_config.gd") + +var _DEFAULT_ANIMATION_LIBRARY = "" # GLOBAL + +func create_animations(target_node: Node, player: AnimationPlayer, aseprite_files: Dictionary, options: Dictionary): + var result = _import(target_node, player, aseprite_files, options) + + if result != result_code.SUCCESS: + printerr(result_code.get_error_message(result)) + + +func _import(target_node: Node, player: AnimationPlayer, aseprite_files: Dictionary, options: Dictionary): + var source_file = aseprite_files.data_file + var sprite_sheet = aseprite_files.sprite_sheet + var data = _aseprite_file_exporter.load_json_content(source_file) + + if not data.is_ok: + return data.code + + var content = data.content + + var context = {} + + if target_node is CanvasItem: + target_node.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST + else: + target_node.texture_filter = BaseMaterial3D.TEXTURE_FILTER_NEAREST + + var texture := _load_texture(sprite_sheet, options.get("should_create_portable_texture", false)) + + _setup_texture(target_node, texture, content, context, options.slice != "") + var result = _configure_animations(target_node, player, content, context, options) + if result != result_code.SUCCESS: + return result + + return _cleanup_animations(target_node, player, content, options) + + +func _load_texture(sprite_sheet: String, use_portable_tex: bool) -> Texture2D: + if use_portable_tex: + return _load_compressed_texture(sprite_sheet) + + var texture = ResourceLoader.load(sprite_sheet, 'Image', ResourceLoader.CACHE_MODE_IGNORE) + texture.take_over_path(sprite_sheet) + return texture + + +func _configure_animations(target_node: Node, player: AnimationPlayer, content: Dictionary, context: Dictionary, options: Dictionary): + var frames = _aseprite.get_content_frames(content) + var slice_rect = null + if options.slice != "": + options["slice_rect"] = _aseprite.get_slice_rect(content, options.slice) + + if not player.has_animation_library(_DEFAULT_ANIMATION_LIBRARY): + player.add_animation_library(_DEFAULT_ANIMATION_LIBRARY, AnimationLibrary.new()) + + if content.meta.has("frameTags") and content.meta.frameTags.size() > 0: + var result = result_code.SUCCESS + for tag in content.meta.frameTags: + var selected_frames = frames.slice(tag.from, tag.to + 1) + result = _add_animation_frames(target_node, player, tag.name, selected_frames, context, options, tag.direction, int(tag.get("repeat", -1))) + if result != result_code.SUCCESS: + break + return result + else: + return _add_animation_frames(target_node, player, "default", frames, context, options) + + +func _add_animation_frames(target_node: Node, player: AnimationPlayer, anim_name: String, frames: Array, context: Dictionary, options: Dictionary, direction = 'forward', repeat = -1): + var animation_name = anim_name + var library_name = _DEFAULT_ANIMATION_LIBRARY + var is_loopable = _config.is_default_animation_loop_enabled() + var slice_rect = options.get("slice_rect") + var is_importing_slice: bool = slice_rect != null + + var anim_tokens := anim_name.split("/") + + if anim_tokens.size() > 2: + push_error("Invalid animation name: %s" % animation_name) + return + elif anim_tokens.size() == 2: + library_name = anim_tokens[0] + animation_name = anim_tokens[1] + + if not _validate_animation_name(animation_name): + push_error("Invalid animation name: %s" % animation_name) + return + + # Create library if doesn't exist + if library_name != _DEFAULT_ANIMATION_LIBRARY and not player.has_animation_library(library_name): + player.add_animation_library(library_name, AnimationLibrary.new()) + + # Check loop + if animation_name.begins_with(_config.get_animation_loop_exception_prefix()): + animation_name = animation_name.substr(_config.get_animation_loop_exception_prefix().length()) + is_loopable = not is_loopable + + # Add library + if not player.get_animation_library(library_name).has_animation(animation_name): + player.get_animation_library(library_name).add_animation(animation_name, Animation.new()) + + var full_name = ( + animation_name if library_name == "" else "%s/%s" % [library_name, animation_name] + ) + + var animation = player.get_animation(full_name) + _cleanup_tracks(target_node, player, animation) + + var frame_track = _get_property_track_path(player, target_node, _get_frame_property(is_importing_slice)) + var frame_track_index = _create_track(target_node, animation, frame_track) + + if direction == "reverse" or direction == "pingpong_reverse": + frames.reverse() + + var animation_length = 0 + + var repetition = 1 + + if repeat != -1: + is_loopable = false + repetition = repeat + + for i in range(repetition): + for frame in frames: + var frame_key = _get_frame_key(target_node, frame, context, slice_rect) + animation.track_insert_key(frame_track_index, animation_length, frame_key) + animation_length += frame.duration / 1000 + + # Godot 4 has an Animation.LOOP_PINGPONG mode, however it does not + # behave like in Aseprite, so I'm keeping the custom implementation + if direction.begins_with("pingpong"): + var working_frames = frames.duplicate() + working_frames.remove_at(working_frames.size() - 1) + if is_loopable or (repetition > 1 and i < repetition - 1): + working_frames.remove_at(0) + working_frames.reverse() + + for frame in working_frames: + var frame_key = _get_frame_key(target_node, frame, context, slice_rect) + animation.track_insert_key(frame_track_index, animation_length, frame_key) + animation_length += frame.duration / 1000 + + # if keep_anim_length is enabled only adjust length if + # - there aren't other tracks besides metas and frame + # - the current animation is shorter than new one + if not options.keep_anim_length or (animation.get_track_count() == 1 or animation.length < animation_length): + animation.length = animation_length + + animation.loop_mode = Animation.LOOP_LINEAR if is_loopable else Animation.LOOP_NONE + + return result_code.SUCCESS + + +const _INVALID_TOKENS := ["/", ":", ",", "["] + + +func _validate_animation_name(name: String) -> bool: + return not _INVALID_TOKENS.any(func(token: String): return token in name) + + +func _create_track(target_node: Node, animation: Animation, track: String) -> int: + var track_index = animation.find_track(track, Animation.TYPE_VALUE) + + if track_index != -1: + animation.remove_track(track_index) + + track_index = animation.add_track(Animation.TYPE_VALUE) + animation.track_set_path(track_index, track) + animation.track_set_interpolation_loop_wrap(track_index, false) + animation.value_track_set_update_mode(track_index, Animation.UPDATE_DISCRETE) + + return track_index + + +func _get_property_track_path(player: AnimationPlayer, target_node: Node, prop: String) -> String: + var node_path = player.get_node(player.root_node).get_path_to(target_node) + return "%s:%s" % [node_path, prop] + + +func _cleanup_animations(target_node: Node, player: AnimationPlayer, content: Dictionary, options: Dictionary): + if not (content.meta.has("frameTags") and content.meta.frameTags.size() > 0): + return result_code.SUCCESS + + _remove_unused_animations(target_node, player, content) + + _hide_unused_nodes(player, content) + + return result_code.SUCCESS + + +## remove tracks and animations for nodes without animation tag +func _remove_unused_animations(target_node: Node, player: AnimationPlayer, content: Dictionary): + var tags: Array[String] = [] + for t in content.meta.frameTags: + tags.push_back(_animation_name_without_loop_prefix(t.name)) + + for a in player.get_animation_list(): + if tags.has(a): + continue + var animation := player.get_animation(a) + + for p in _get_props_to_cleanup(): + var track = _get_property_track_path(player, target_node, p) + var track_index = animation.find_track(track, Animation.TYPE_VALUE) + if track_index != -1: + animation.remove_track(track_index) + + + if animation.get_track_count() == 0: + var p = _get_animation_data(a) + player.get_animation_library(p.library).remove_animation(p.animation) + + +## control visibility track when node has "hide unused" option available +func _hide_unused_nodes(player: AnimationPlayer, content: Dictionary): + var root_node := player.get_node(player.root_node) + var all_animations := player.get_animation_list() + var all_sprite_nodes: Array[Node] = [] + var animation_sprites := {} + + for a in all_animations: + var animation := player.get_animation(a) + var sprite_nodes: Array[Node] = [] + + # get all supported nodes in animation + for track_idx in animation.get_track_count(): + var raw_path := animation.track_get_path(track_idx) + + var path := _remove_properties_from_path(raw_path) + var sprite_node := root_node.get_node(path) + + if not _is_supported_node(sprite_node): + continue + + # ignore nodes with no wizard config or not supposed to be hidden + if not wizard_config.has_config(sprite_node) or not wizard_config.load_config(sprite_node).get("set_vis_track", false): + continue + + if not sprite_nodes.has(sprite_node): + sprite_nodes.append(sprite_node) + if not all_sprite_nodes.has(sprite_node): + all_sprite_nodes.append(sprite_node) + + animation_sprites[animation] = sprite_nodes + + for animation: Animation in animation_sprites: + var sprite_nodes : Array[Node] = animation_sprites[animation] + for node in all_sprite_nodes: + # node should be visible if they are in the list and have tracks available + var node_visibility: bool = sprite_nodes.has(node) and _relevant_track_count(node, player, animation) > 0 + var visible_track := _get_property_track_path(player, node, "visible") + var visible_track_index := _create_track(node, animation, visible_track) + animation.track_insert_key(visible_track_index, 0, node_visibility) + + +func list_layers(file: String, only_visibles = false) -> Array: + return _aseprite.list_layers(file, only_visibles) + + +func list_slices(file: String) -> Array: + return _aseprite.list_slices(file) + + +func _remove_properties_from_path(path: NodePath) -> NodePath: + var string_path := path as String + if !(":" in string_path): + return string_path as NodePath + + var property_path := path.get_concatenated_subnames() as String + string_path = string_path.substr(0, string_path.length() - property_path.length() - 1) + + return string_path as NodePath + + +func _cleanup_tracks(target_node: Node, player: AnimationPlayer, animation: Animation): + for track_key in ["texture", "hframes", "vframes", "region_rect", "frame"]: + var track = _get_property_track_path(player, target_node, track_key) + var track_index = animation.find_track(track, Animation.TYPE_VALUE) + if track_index != -1: + animation.remove_track(track_index) + + +func _setup_texture(target_node: Node, texture: Texture2D, content: Dictionary, context: Dictionary, is_importing_slice: bool): + push_error("_setup_texture not implemented!") + + +func _get_frame_property(is_importing_slice: bool) -> String: + push_error("_get_frame_property not implemented!") + return "" + + +func _get_frame_key(target_node: Node, frame: Dictionary, context: Dictionary, slice_info: Variant): + push_error("_get_frame_key not implemented!") + + +func _get_props_to_cleanup() -> Array[String]: + push_error("_props_to_cleanup not implemented!") + return [] + + +func _is_supported_node(target_node: Node): + return target_node is Sprite2D or target_node is Sprite3D or target_node is TextureRect + + +func _get_animation_data(animaton_name: String) -> Dictionary: + var parts = animaton_name.split("/") + + if parts.size() == 2: + return { + "library": parts[0], + "animation": parts[1], + } + return { + "library": _DEFAULT_ANIMATION_LIBRARY, + "animation": parts[0], + } + + +func _relevant_track_count(target_node: Node, player: AnimationPlayer, animation: Animation) -> int: + var track_count := 0 + for p in _get_props_to_cleanup(): + if p == "visible": + continue + var track = _get_property_track_path(player, target_node, p) + var track_index = animation.find_track(track, Animation.TYPE_VALUE) + if track_index != -1: + track_count += 1 + + return track_count + + +func _animation_name_without_loop_prefix(animation_name: String) -> String: + if animation_name.begins_with(_config.get_animation_loop_exception_prefix()): + return animation_name.substr(_config.get_animation_loop_exception_prefix().length()) + return animation_name diff --git a/hexmapper/addons/AsepriteWizard/creators/animation_player/animation_creator.gd.uid b/hexmapper/addons/AsepriteWizard/creators/animation_player/animation_creator.gd.uid new file mode 100644 index 0000000..8d4dd3e --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/creators/animation_player/animation_creator.gd.uid @@ -0,0 +1 @@ +uid://c5gvrr4hajril diff --git a/hexmapper/addons/AsepriteWizard/creators/animation_player/sprite_animation_creator.gd b/hexmapper/addons/AsepriteWizard/creators/animation_player/sprite_animation_creator.gd new file mode 100644 index 0000000..07f220e --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/creators/animation_player/sprite_animation_creator.gd @@ -0,0 +1,49 @@ +extends "animation_creator.gd" + + +func _setup_texture(sprite: Node, texture: Texture2D, content: Dictionary, context: Dictionary, is_importing_slice: bool): + sprite.texture = texture + + if content.frames.is_empty(): + return + + if is_importing_slice: + sprite.region_enabled = true + sprite.hframes = 1 + sprite.vframes = 1 + sprite.frame = 0 + else: + sprite.region_enabled = false + sprite.hframes = content.meta.size.w / content.frames[0].sourceSize.w + sprite.vframes = content.meta.size.h / content.frames[0].sourceSize.h + + +func _get_frame_property(is_importing_slice: bool) -> String: + return "frame" if not is_importing_slice else "region_rect" + + +func _get_props_to_cleanup() -> Array[String]: + return ["frame", "region_rect", "visible"] + + + +func _get_frame_key(sprite: Node, frame: Dictionary, context: Dictionary, slice_info: Variant): + if slice_info != null: + return _create_slice_rect(frame, slice_info) + return _calculate_frame_index(sprite,frame) + + +func _calculate_frame_index(sprite: Node, frame: Dictionary) -> int: + var column = floor(frame.frame.x * sprite.hframes / sprite.texture.get_width()) + var row = floor(frame.frame.y * sprite.vframes / sprite.texture.get_height()) + return (row * sprite.hframes) + column + + +func _create_slice_rect(frame_data: Dictionary, slice_rect: Rect2) -> Rect2: + var frame = frame_data.frame + return Rect2( + frame.x + slice_rect.position.x, + frame.y + slice_rect.position.y, + slice_rect.size.x, + slice_rect.size.y + ) diff --git a/hexmapper/addons/AsepriteWizard/creators/animation_player/sprite_animation_creator.gd.uid b/hexmapper/addons/AsepriteWizard/creators/animation_player/sprite_animation_creator.gd.uid new file mode 100644 index 0000000..c2776e7 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/creators/animation_player/sprite_animation_creator.gd.uid @@ -0,0 +1 @@ +uid://dsl612cp252oh diff --git a/hexmapper/addons/AsepriteWizard/creators/animation_player/texture_rect_animation_creator.gd b/hexmapper/addons/AsepriteWizard/creators/animation_player/texture_rect_animation_creator.gd new file mode 100644 index 0000000..22a4e1d --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/creators/animation_player/texture_rect_animation_creator.gd @@ -0,0 +1,32 @@ +extends "animation_creator.gd" + + +func _setup_texture(target_node: Node, texture: Texture2D, content: Dictionary, context: Dictionary, _is_importing_slice: bool): + context["base_texture"] = texture + + +func _get_frame_property(_is_importing_slice: bool) -> String: + return "texture" + + +func _get_props_to_cleanup() -> Array[String]: + return ["texture", "visible"] + + +func _get_frame_key(target_node: Node, frame: Dictionary, context: Dictionary, slice_info: Variant): + return _get_atlas_texture(context["base_texture"], frame, slice_info) + + +func _get_atlas_texture(base_texture: Texture2D, frame_data: Dictionary, slice_info: Variant) -> AtlasTexture: + var tex = AtlasTexture.new() + tex.atlas = base_texture + tex.region = Rect2(Vector2(frame_data.frame.x, frame_data.frame.y), Vector2(frame_data.frame.w, frame_data.frame.h)) + tex.filter_clip = true + + if slice_info != null: + tex.region.position.x += slice_info.position.x + tex.region.position.y += slice_info.position.y + tex.region.size.x = slice_info.size.x + tex.region.size.y = slice_info.size.y + + return tex diff --git a/hexmapper/addons/AsepriteWizard/creators/animation_player/texture_rect_animation_creator.gd.uid b/hexmapper/addons/AsepriteWizard/creators/animation_player/texture_rect_animation_creator.gd.uid new file mode 100644 index 0000000..ae495c9 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/creators/animation_player/texture_rect_animation_creator.gd.uid @@ -0,0 +1 @@ +uid://bc0a36kt8g48t diff --git a/hexmapper/addons/AsepriteWizard/creators/base_sprite_resource_creator.gd b/hexmapper/addons/AsepriteWizard/creators/base_sprite_resource_creator.gd new file mode 100644 index 0000000..547abda --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/creators/base_sprite_resource_creator.gd @@ -0,0 +1,15 @@ +@tool +extends RefCounted + +var result_code = preload("../config/result_codes.gd") +var _aseprite = preload("../aseprite/aseprite.gd").new() +var _aseprite_file_exporter = preload("../aseprite/file_exporter.gd").new() + +var _config = preload("../config/config.gd").new() + + +func _load_compressed_texture(sprite_sheet: String) -> PortableCompressedTexture2D: + var image = Image.load_from_file(sprite_sheet) + var tex := PortableCompressedTexture2D.new() + tex.create_from_image(image, PortableCompressedTexture2D.COMPRESSION_MODE_LOSSLESS) + return tex diff --git a/hexmapper/addons/AsepriteWizard/creators/base_sprite_resource_creator.gd.uid b/hexmapper/addons/AsepriteWizard/creators/base_sprite_resource_creator.gd.uid new file mode 100644 index 0000000..93ef2f5 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/creators/base_sprite_resource_creator.gd.uid @@ -0,0 +1 @@ +uid://cahr0h02r8nt2 diff --git a/hexmapper/addons/AsepriteWizard/creators/sprite_frames/sprite_frames_creator.gd b/hexmapper/addons/AsepriteWizard/creators/sprite_frames/sprite_frames_creator.gd new file mode 100644 index 0000000..f02d847 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/creators/sprite_frames/sprite_frames_creator.gd @@ -0,0 +1,284 @@ +@tool +extends "../base_sprite_resource_creator.gd" + +enum { + FILE_EXPORT_MODE, + LAYERS_EXPORT_MODE +} + +### +### Create SpriteFrames from aseprite files and insert +### them to the animated_sprite node +### +func create_animations(animated_sprite: Node, aseprite_files: Dictionary, options: Dictionary) -> void: + var sprite_frames_result = _create_sprite_frames(aseprite_files, options) + if not sprite_frames_result.is_ok: + printerr(result_code.get_error_message(sprite_frames_result.code)) + return + + animated_sprite.frames = sprite_frames_result.content.resource + + if animated_sprite is CanvasItem: + animated_sprite.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST + else: + animated_sprite.texture_filter = BaseMaterial3D.TEXTURE_FILTER_NEAREST + + +func create_resources(source_files: Array, options: Dictionary = {}) -> Dictionary: + var resources = [] + + for o in source_files: + if o.is_empty(): + return result_code.error(result_code.ERR_ASEPRITE_EXPORT_FAILED) + + var result = _create_sprite_frames(o, options) + + if not result.is_ok: + return result + + resources.push_back({ + "data_file": o.data_file, + "resource": result.content.resource, + "extra_gen_files": result.content.extra_gen_files + }) + + return result_code.result(resources) + + +func _create_sprite_frames(data: Dictionary, options: Dictionary) -> Dictionary: + var aseprite_resources = _load_aseprite_resources(data, options) + if not aseprite_resources.is_ok: + return aseprite_resources + + var resource = _create_sprite_frames_with_animations( + aseprite_resources.content.metadata, + aseprite_resources.content.texture, + options, + ) + + return result_code.result({ + "resource": resource, + "extra_gen_files": aseprite_resources.content.extra_gen_files + }) + +func _load_aseprite_resources(aseprite_data: Dictionary, options: Dictionary) -> Dictionary: + var content_result = _aseprite_file_exporter.load_json_content(aseprite_data.data_file) + + if not content_result.is_ok: + return content_result + + var result = _load_or_create_texture_resource(aseprite_data.sprite_sheet, options) + + return result_code.result({ + "metadata": content_result.content, + "texture": result.texture, + "extra_gen_files": result.extra_gen_files + }) + + +func _load_or_create_texture_resource(sprite_sheet: String, options: Dictionary) -> Dictionary: + if not options.get("should_create_portable_texture", false): + return { "texture": _load_texture(sprite_sheet), "extra_gen_files": [] } + + if options.get("sheet_base_path", "") == "": + return { + "texture": create_packed_texture(sprite_sheet), + "extra_gen_files": [] + } + + var texture_path = "%s.%s.texture.res" % [options.sheet_base_path, sprite_sheet.get_file().get_basename() ] + + return { + "texture": create_packed_texture(sprite_sheet, texture_path), + "extra_gen_files": [texture_path] + } + + +func save_resources(resources: Array) -> int: + for resource in resources: + var code = _save_resource(resource.resource, resource.data_file) + if code != OK: + return code + return OK + + +func _save_resource(resource, source_path: String) -> int: + var save_path = "%s.%s" % [source_path.get_basename(), "res"] + var code = ResourceSaver.save(resource, save_path, ResourceSaver.FLAG_REPLACE_SUBRESOURCE_PATHS) + resource.take_over_path(save_path) + return code + + +func _create_sprite_frames_with_animations(content: Dictionary, texture, options: Dictionary) -> SpriteFrames: + var frame_cache = {} + var frames = _aseprite.get_content_frames(content) + var sprite_frames := SpriteFrames.new() + sprite_frames.remove_animation("default") + + var frame_rect: Variant = null + + # currently, aseprite does not work with the --slice option, so we need to manually + # do it. https://github.com/aseprite/aseprite/issues/2469 + if options.get("slice", "") != "": + frame_rect = _aseprite.get_slice_rect(content, options.slice) + + if content.meta.has("frameTags") and content.meta.frameTags.size() > 0: + for tag in content.meta.frameTags: + var selected_frames = frames.slice(tag.from, tag.to + 1) + _add_animation_frames( + sprite_frames, + tag.name, + selected_frames, + texture, + frame_rect, + { "should_round_fps": options.get("should_round_fps", true) }, + tag.direction, + int(tag.get("repeat", -1)), + frame_cache + ) + else: + _add_animation_frames(sprite_frames, "default", frames, texture, frame_rect, { "should_round_fps": options.get("should_round_fps", true) }) + + return sprite_frames + + +func _add_animation_frames( + sprite_frames: SpriteFrames, + anim_name: String, + frames: Array, + texture, + frame_rect: Variant, + options: Dictionary, + direction = 'forward', + repeat = -1, + frame_cache = {} +): + var animation_name := anim_name + var is_loopable = _config.is_default_animation_loop_enabled() + + var loop_prefix = _config.get_animation_loop_exception_prefix() + if animation_name.begins_with(loop_prefix): + animation_name = anim_name.trim_prefix(loop_prefix) + is_loopable = not is_loopable + + sprite_frames.add_animation(animation_name) + + var min_duration = _get_min_duration(frames) + var fps = _calculate_fps(min_duration, options.should_round_fps) + + if direction == "reverse" or direction == "pingpong_reverse": + frames.reverse() + + var repetition = 1 + + if repeat != -1: + is_loopable = false + repetition = repeat + + for i in range(repetition): + for frame in frames: + _add_to_sprite_frames(sprite_frames, animation_name, texture, frame, min_duration, frame_cache, frame_rect) + + if direction.begins_with("pingpong"): + var working_frames = frames.duplicate() + working_frames.remove_at(working_frames.size() - 1) + if is_loopable or (repetition > 1 and i < repetition - 1): + working_frames.remove_at(0) + working_frames.reverse() + + for frame in working_frames: + _add_to_sprite_frames(sprite_frames, animation_name, texture, frame, min_duration, frame_cache, frame_rect) + + sprite_frames.set_animation_loop(animation_name, is_loopable) + sprite_frames.set_animation_speed(animation_name, fps) + + +func _calculate_fps(min_duration: int, should_round: bool) -> float: + if should_round: + return ceil(1000.0 / min_duration) + return 1000.0 / min_duration + + +func _get_min_duration(frames) -> int: + var min_duration = 100000 + for frame in frames: + if frame.duration < min_duration: + min_duration = frame.duration + return min_duration + + +func _load_texture(path) -> CompressedTexture2D: + ResourceLoader.load_threaded_request(path, "CompressedTexture2D", false, ResourceLoader.CACHE_MODE_REPLACE) + return ResourceLoader.load_threaded_get(path) + + +func create_packed_texture(sprite_sheet: String, save_path: String = "") -> PortableCompressedTexture2D: + var tex := _load_compressed_texture(sprite_sheet) + # if no path was provided, we just want the texture in memory + if save_path == "": + return tex + + var exit_code = ResourceSaver.save(tex, save_path) + if exit_code != OK: + printerr(result_code.get_error_message(result_code.ERR_ASEPRITE_EXPORT_FAILED)) + return null + + return ResourceLoader.load(save_path) + + +func _add_to_sprite_frames( + sprite_frames, + animation_name: String, + texture, + frame: Dictionary, + min_duration: int, + frame_cache: Dictionary, + frame_rect: Variant, +): + var atlas : AtlasTexture = _create_atlastexture_from_frame(texture, frame, sprite_frames, frame_cache, frame_rect) + var duration = frame.duration / min_duration + sprite_frames.add_frame(animation_name, atlas, duration) + + +func _create_atlastexture_from_frame( + image, + frame_data, + sprite_frames: SpriteFrames, + frame_cache: Dictionary, + frame_rect: Variant, +) -> AtlasTexture: + var frame = frame_data.frame + var region := Rect2(frame.x, frame.y, frame.w, frame.h) + + # this is to manually set the slice + if frame_rect != null: + region.position.x += frame_rect.position.x + region.position.y += frame_rect.position.y + region.size.x = frame_rect.size.x + region.size.y = frame_rect.size.y + + var key := "%s_%s_%s_%s" % [frame.x, frame.y, frame.w, frame.h] + var texture = frame_cache.get(key) + + if texture != null and texture.atlas == image: + return texture + + var atlas_texture := AtlasTexture.new() + atlas_texture.atlas = image + atlas_texture.region = region + + frame_cache[key] = atlas_texture + + return atlas_texture + + +func list_layers(file: String, only_visibles = false) -> Array: + return _aseprite.list_layers(file, only_visibles) + + +func list_slices(file: String) -> Array: + return _aseprite.list_slices(file) + + +func _get_file_basename(file_path: String) -> String: + return file_path.get_file().trim_suffix('.%s' % file_path.get_extension()) diff --git a/hexmapper/addons/AsepriteWizard/creators/sprite_frames/sprite_frames_creator.gd.uid b/hexmapper/addons/AsepriteWizard/creators/sprite_frames/sprite_frames_creator.gd.uid new file mode 100644 index 0000000..b517099 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/creators/sprite_frames/sprite_frames_creator.gd.uid @@ -0,0 +1 @@ +uid://dl8ny6cpqq0sj diff --git a/hexmapper/addons/AsepriteWizard/creators/static_texture/texture_creator.gd b/hexmapper/addons/AsepriteWizard/creators/static_texture/texture_creator.gd new file mode 100644 index 0000000..3505f2d --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/creators/static_texture/texture_creator.gd @@ -0,0 +1,31 @@ +@tool +extends "../base_sprite_resource_creator.gd" + +func load_texture(target_node: Node, aseprite_files: Dictionary, options: Dictionary) -> void: + var source_file = aseprite_files.data_file + var sprite_sheet = aseprite_files.sprite_sheet + var data = _aseprite_file_exporter.load_json_content(source_file) + var texture + + if options.get("should_create_portable_texture", false): + texture = _load_compressed_texture(sprite_sheet) + else: + texture = ResourceLoader.load(sprite_sheet) + + if not data.is_ok: + printerr("Failed to load aseprite source %s" % source_file) + return + + if options.slice == "": + target_node.texture = texture + else: + var region = _aseprite.get_slice_rect(data.content, options.slice) + var atlas_texture := AtlasTexture.new() + atlas_texture.atlas = texture + atlas_texture.region = region + target_node.texture = atlas_texture + + if target_node is CanvasItem: + target_node.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST + else: + target_node.texture_filter = BaseMaterial3D.TEXTURE_FILTER_NEAREST diff --git a/hexmapper/addons/AsepriteWizard/creators/static_texture/texture_creator.gd.uid b/hexmapper/addons/AsepriteWizard/creators/static_texture/texture_creator.gd.uid new file mode 100644 index 0000000..66f91e1 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/creators/static_texture/texture_creator.gd.uid @@ -0,0 +1 @@ +uid://ywvg22ffi7cx diff --git a/hexmapper/addons/AsepriteWizard/export/export_plugin.gd b/hexmapper/addons/AsepriteWizard/export/export_plugin.gd new file mode 100644 index 0000000..bed928a --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/export/export_plugin.gd @@ -0,0 +1,119 @@ +## This export plugin makes sure all textures are included in +## the exported game and also remove any metadata that could +## potentially leak information about paths in the host system. +extends EditorExportPlugin + +const wizard_config = preload("../config/wizard_config.gd") + +func _get_name(): + return "aseprite_wizard_metadata_export_plugin" + + +func _export_file(path: String, type: String, features: PackedStringArray) -> void: + match type: + "PackedScene": + _cleanup_scene(path, type) + "SpriteFrames": + _handle_spriteframes(path, type) + + +func _cleanup_scene(path: String, type: String): + var scene : PackedScene = ResourceLoader.load(path, type, ResourceLoader.CACHE_MODE_IGNORE) + var scene_changed := false + var root_node := scene.instantiate(PackedScene.GEN_EDIT_STATE_INSTANCE) + var nodes := [root_node] + + #remove_at metadata from scene + while not nodes.is_empty(): + var node : Node = nodes.pop_front() + + for child in node.get_children(): + nodes.push_back(child) + + if _remove_meta(node): + scene_changed = true + + #save scene if changed + if scene_changed: + var filtered_scene := PackedScene.new() + if filtered_scene.pack(root_node) != OK: + print("Error updating scene") + return + + var content := _get_scene_content(path, filtered_scene) + + add_file(path, content, true) + + root_node.free() + + +func _remove_meta(node: Object) -> bool: + if node.has_meta(wizard_config.WIZARD_CONFIG_META_NAME): + node.remove_meta(wizard_config.WIZARD_CONFIG_META_NAME) + return true + + return false + + +func _get_scene_content(path:String, scene:PackedScene) -> PackedByteArray: + var tmp_path = OS.get_cache_dir() + "tmp_scene." + path.get_extension() + ResourceSaver.save(scene, tmp_path) + + var tmp_file = FileAccess.open(tmp_path, FileAccess.READ) + var content : PackedByteArray = tmp_file.get_buffer(tmp_file.get_length()) + tmp_file.close() + + if FileAccess.file_exists(tmp_path): + DirAccess.remove_absolute(tmp_path) + + return content + +## As of today, Godot only includes in the export the resources +## directly referenced by the import plugin. +## To make the generated textures available, I need to explicitly +## add them to the exported package. +func _import_extra_textures(node: SpriteFrames): + # check if this is a wizard import + if not node.has_meta("imported_via_aw"): + return + + var animations = node.get_animation_names() + var textures = [] + for animation in animations: + var frame_count = node.get_frame_count(animation) + for idx in range(frame_count): + var atlas = node.get_frame_texture(animation, idx) + if atlas == null: + continue + var tex = atlas.atlas + if tex == null: + continue + if not textures.has(tex.resource_path): + textures.push_back(tex.resource_path) + + for texture_path in textures: + var file = FileAccess.open(texture_path, FileAccess.READ) + var content : PackedByteArray = file.get_buffer(file.get_length()) + add_file(texture_path, content, false) + + +func _handle_spriteframes(path: String, type: String): + var resource : SpriteFrames = ResourceLoader.load(path, type, ResourceLoader.CACHE_MODE_IGNORE) + _import_extra_textures(resource) + if _remove_meta(resource): + var content := _create_temp_resource(path, resource) + add_file(path, content, true) + + +func _create_temp_resource(path: String, resource: SpriteFrames) -> PackedByteArray: + var tmp_path = OS.get_cache_dir() + "tmp_spriteframes_resource." + path.get_extension() + ResourceSaver.save(resource, tmp_path) + + var tmp_file = FileAccess.open(tmp_path, FileAccess.READ) + var content : PackedByteArray = tmp_file.get_buffer(tmp_file.get_length()) + tmp_file.close() + + if FileAccess.file_exists(tmp_path): + DirAccess.remove_absolute(tmp_path) + + return content diff --git a/hexmapper/addons/AsepriteWizard/export/export_plugin.gd.uid b/hexmapper/addons/AsepriteWizard/export/export_plugin.gd.uid new file mode 100644 index 0000000..59cf2ff --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/export/export_plugin.gd.uid @@ -0,0 +1 @@ +uid://b6ag7a1rlkjip diff --git a/hexmapper/addons/AsepriteWizard/importers/helpers/file_system_helper.gd b/hexmapper/addons/AsepriteWizard/importers/helpers/file_system_helper.gd new file mode 100644 index 0000000..a393e8f --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/helpers/file_system_helper.gd @@ -0,0 +1,22 @@ +@tool +extends Node + +const WAIT_TIME_IN_SECONDS := 0.8 +var _time_left := 0.0 +var _scheduled := false + +## Schedule a file system scan. This method works like a debouncer +## postponing the scan until no more calls are being made +func schedule_file_system_scan() -> void: + _time_left = WAIT_TIME_IN_SECONDS + _scheduled = true + + +func _process(delta: float) -> void: + if _scheduled: + if _time_left > 0.0: + _time_left -= delta + else: + _scheduled = false + if not EditorInterface.get_resource_filesystem().is_scanning(): + EditorInterface.get_resource_filesystem().scan.call_deferred() diff --git a/hexmapper/addons/AsepriteWizard/importers/helpers/file_system_helper.gd.uid b/hexmapper/addons/AsepriteWizard/importers/helpers/file_system_helper.gd.uid new file mode 100644 index 0000000..23c88e7 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/helpers/file_system_helper.gd.uid @@ -0,0 +1 @@ +uid://bivugcpjlxeiv diff --git a/hexmapper/addons/AsepriteWizard/importers/multiple_import_plugin_base.gd b/hexmapper/addons/AsepriteWizard/importers/multiple_import_plugin_base.gd new file mode 100644 index 0000000..ab88f8b --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/multiple_import_plugin_base.gd @@ -0,0 +1,117 @@ +@tool +extends EditorImportPlugin + +const result_codes = preload("../config/result_codes.gd") + +var config = preload("../config/config.gd").new() +var _aseprite = preload("../aseprite/aseprite.gd").new() + +var file_system_helper + +func _init(fs_helper) -> void: + file_system_helper = fs_helper + + +func _get_recognized_extensions(): + return ["aseprite", "ase"] + + +func _get_save_extension(): + return "json" + + +func _get_resource_type(): + return "JSON" + + +func _get_preset_count(): + return 1 + + +func _get_preset_name(i): + return "Default" + + +func _get_import_order(): + return 1 + + +func _get_option_visibility(path, option, options): + return true + + +func _import(source_file, save_path, options, platform_variants, gen_files): + var old_data = _load_old_data(source_file) + var exception_pattern = options.get('layer/exclude_layers_pattern', "") + var should_include_only_visibles = options.get('layer/only_visible_layers', false) + + var absolute_source_file = ProjectSettings.globalize_path(source_file) + + var layers = _aseprite.list_valid_layers( + absolute_source_file, + exception_pattern, + should_include_only_visibles + ) + + var layers_resources_folder = options["output/layers_resources_folder"] + + var import_options = _get_base_import_options(options) + import_options["source"] = source_file + + var base_name = source_file.get_basename() + + if layers_resources_folder != "": + if not DirAccess.dir_exists_absolute(layers_resources_folder): + DirAccess.make_dir_recursive_absolute(layers_resources_folder) + base_name = "%s/%s" % [layers_resources_folder, base_name.get_file()] + + var data_to_save = { + "layers": {} + } + + for layer in layers: + var layer_save_path = "%s_l_%s.%s" % [base_name, layer, _layer_extension()] + var file = FileAccess.open(layer_save_path, FileAccess.WRITE) + file.store_string(JSON.stringify({ + "layer": layer, + "import_options": import_options, + })) + data_to_save.layers[layer] = layer_save_path + + var json = JSON.new() + json.data = data_to_save + + var exit_code = ResourceSaver.save(json, "%s.%s" % [save_path, _get_save_extension()]) + + _cleanup_old_layers(old_data, layers) + + file_system_helper.schedule_file_system_scan() + + return exit_code + + +func _layer_extension() -> String: + return "" + +func _get_base_import_options(options: Dictionary): + return {} + + +func _load_old_data(source_file: String): + var old_data = {} + + if ResourceLoader.exists(source_file): + var d = ResourceLoader.load(source_file) + if d is JSON: + old_data = d.data.layers + + return old_data + + +func _cleanup_old_layers(old_data: Dictionary, layers: Array): + var old_layers = old_data.keys() + for old_layer in old_layers: + if not layers.has(old_layer): + var file = old_data[old_layer] + if FileAccess.file_exists(file): + DirAccess.remove_absolute(file) diff --git a/hexmapper/addons/AsepriteWizard/importers/multiple_import_plugin_base.gd.uid b/hexmapper/addons/AsepriteWizard/importers/multiple_import_plugin_base.gd.uid new file mode 100644 index 0000000..33502e0 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/multiple_import_plugin_base.gd.uid @@ -0,0 +1 @@ +uid://berv346k540w7 diff --git a/hexmapper/addons/AsepriteWizard/importers/noop_import_plugin.gd b/hexmapper/addons/AsepriteWizard/importers/noop_import_plugin.gd new file mode 100644 index 0000000..76e5d0b --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/noop_import_plugin.gd @@ -0,0 +1,57 @@ +@tool +extends EditorImportPlugin + +## +## No-op importer to allow files to be seen and +## managed, but without triggering a real import +## + +var config = preload("../config/config.gd").new() + +func _get_importer_name(): + return "aseprite_wizard.plugin.noop" + + +func _get_visible_name(): + return "Aseprite (No Import)" + + +func _get_recognized_extensions(): + return ["aseprite", "ase"] + + +func _get_save_extension(): + return "res" + + +func _get_resource_type(): + return "PackedDataContainer" + + +func _get_preset_count(): + return 1 + + +func _get_preset_name(i): + return "Default" + + +func _get_priority(): + return 2.0 if config.get_default_importer() == config.IMPORTER_NOOP_NAME else 1.0 + + +func _get_import_order(): + return 1 + + +func _get_import_options(_path, _i): + return [] + + +func _get_option_visibility(path, option, options): + return true + + +func _import(source_file, save_path, options, platform_variants, gen_files): + var container = PackedDataContainer.new() + return ResourceSaver.save(container, "%s.%s" % [save_path, _get_save_extension()]) diff --git a/hexmapper/addons/AsepriteWizard/importers/noop_import_plugin.gd.uid b/hexmapper/addons/AsepriteWizard/importers/noop_import_plugin.gd.uid new file mode 100644 index 0000000..aa1cb84 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/noop_import_plugin.gd.uid @@ -0,0 +1 @@ +uid://cf00cl8s3dvod diff --git a/hexmapper/addons/AsepriteWizard/importers/split_layer_importers/layer_import_plugin.gd b/hexmapper/addons/AsepriteWizard/importers/split_layer_importers/layer_import_plugin.gd new file mode 100644 index 0000000..0d6bb56 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/split_layer_importers/layer_import_plugin.gd @@ -0,0 +1,112 @@ +@tool +extends EditorImportPlugin + +const result_codes = preload("../../config/result_codes.gd") + +var config = preload("../../config/config.gd").new() +var _aseprite = preload("../../aseprite/aseprite.gd").new() +var _sf_creator = preload("../../creators/sprite_frames/sprite_frames_creator.gd").new() + + +func _get_importer_name(): + return "aseprite_wizard.plugin.spriteframes-split-layer" + + +func _get_visible_name(): + return "Aseprite Layer SpriteFrames" + + +func _get_recognized_extensions(): + return ["ase_layer"] + + +func _get_save_extension(): + return "res" + + +func _get_resource_type(): + return "SpriteFrames" + + +func _get_preset_count(): + return 1 + + +func _get_preset_name(i): + return "Default" + + +func _get_priority(): + return 1.0 + + +func _get_import_order(): + return 1 + + +func _get_import_options(_path, _i): + return [] + + +func _get_option_visibility(path, option, options): + return true + + +func _import(source_file, save_path, options, platform_variants, gen_files): + var file = FileAccess.open(source_file, FileAccess.READ) + var data = JSON.parse_string(file.get_as_text()) + + var source_path = source_file.get_base_dir() + + var absolute_source_file = ProjectSettings.globalize_path(data.import_options.source) + + var export_options = { + "sheet_type": data.import_options.sheet_type, + "sheet_columns": data.import_options.sheet_columns, + "should_round_fps": data.import_options.should_round_fps, + } + + var source_files = _aseprite.export_file_with_layers( + absolute_source_file, + [data.layer], + source_path, + export_options, + ) + + if source_files.is_empty(): + printerr("ERROR - Could not import aseprite file. Layer not found.") + return FAILED +# + var resources = _sf_creator.create_resources([source_files], { + "should_round_fps": data.import_options.should_round_fps, + "should_create_portable_texture": true, + "sheet_base_path": save_path, + }) + + if not resources.is_ok: + printerr("ERROR - Could not import aseprite file: %s" % result_codes.get_error_message(resources.code)) + return FAILED + + var resource = resources.content[0] + resource.resource.set_meta("imported_via_aw", true) + + var resource_path = "%s.res" % save_path + var exit_code = ResourceSaver.save(resource.resource, resource_path) + resource.resource.take_over_path(resource_path) + + for extra_file in resource.extra_gen_files: + gen_files.push_back(extra_file) +# + if config.should_remove_source_files(): + _remove_source_files(source_files) + + if exit_code != OK: + printerr("ERROR - Could not persist aseprite file: %s" % result_codes.get_error_message(exit_code)) + return FAILED + + return OK + + +func _remove_source_files(source_files: Dictionary): + DirAccess.remove_absolute(source_files.data_file) + DirAccess.remove_absolute(source_files.sprite_sheet) diff --git a/hexmapper/addons/AsepriteWizard/importers/split_layer_importers/layer_import_plugin.gd.uid b/hexmapper/addons/AsepriteWizard/importers/split_layer_importers/layer_import_plugin.gd.uid new file mode 100644 index 0000000..1b16bfb --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/split_layer_importers/layer_import_plugin.gd.uid @@ -0,0 +1 @@ +uid://ccsolt4jb8f67 diff --git a/hexmapper/addons/AsepriteWizard/importers/split_layer_importers/layer_texture_import_plugin.gd b/hexmapper/addons/AsepriteWizard/importers/split_layer_importers/layer_texture_import_plugin.gd new file mode 100644 index 0000000..5591508 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/split_layer_importers/layer_texture_import_plugin.gd @@ -0,0 +1,52 @@ +@tool +extends "../static_texture_import_plugin_base.gd" + +## +## Static texture importer (Split). +## Imports first frame from Aseprite file as texture in multiple resources +## + +func _get_importer_name(): + return "aseprite_wizard.plugin.static-texture-split-layer" + + +func _get_visible_name(): + return "Aseprite Layer Texture" + + +func _get_recognized_extensions(): + return ["ase_layer_tex"] + + +func _get_priority(): + return 1.0 + + +func _get_import_options(_path, _i): + return [] + + +func _import(source_file, save_path, options, platform_variants, gen_files): + var file = FileAccess.open(source_file, FileAccess.READ) + var i_data = JSON.parse_string(file.get_as_text()) + + var source_path = source_file.get_base_dir() + var absolute_source_file = ProjectSettings.globalize_path(i_data.import_options.source) + + var aseprite_opts = { + "layer": i_data.layer, + "output_filename": '', + "output_folder": source_path, + "first_frame_only": true, + } + + var result = _generate_texture(absolute_source_file, aseprite_opts) + + if not result.is_ok: + printerr("ERROR - Could not import aseprite file: %s" % result_codes.get_error_message(result.code)) + return FAILED + + var sprite_sheet = result.content.sprite_sheet + var data = result.content.data + + return _save_resource(sprite_sheet, save_path, result.content.data_file, data.meta.size) diff --git a/hexmapper/addons/AsepriteWizard/importers/split_layer_importers/layer_texture_import_plugin.gd.uid b/hexmapper/addons/AsepriteWizard/importers/split_layer_importers/layer_texture_import_plugin.gd.uid new file mode 100644 index 0000000..f248b44 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/split_layer_importers/layer_texture_import_plugin.gd.uid @@ -0,0 +1 @@ +uid://csoj3wh7nal3h diff --git a/hexmapper/addons/AsepriteWizard/importers/sprite_frames_import_plugin.gd b/hexmapper/addons/AsepriteWizard/importers/sprite_frames_import_plugin.gd new file mode 100644 index 0000000..9aa2b25 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/sprite_frames_import_plugin.gd @@ -0,0 +1,125 @@ +@tool +extends EditorImportPlugin + +const result_codes = preload("../config/result_codes.gd") + +var config = preload("../config/config.gd").new() +var _aseprite_file_exporter = preload("../aseprite/file_exporter.gd").new() +var _sf_creator = preload("../creators/sprite_frames/sprite_frames_creator.gd").new() +var file_system: EditorFileSystem = EditorInterface.get_resource_filesystem() + + +func _get_importer_name(): + return "aseprite_wizard.plugin.spriteframes" + + +func _get_visible_name(): + return "Aseprite SpriteFrames" + + +func _get_recognized_extensions(): + return ["aseprite", "ase"] + + +func _get_save_extension(): + return "res" + + +func _get_resource_type(): + return "SpriteFrames" + + +func _get_preset_count(): + return 1 + + +func _get_preset_name(i): + return "Default" + + +func _get_priority(): + return 2.0 if config.get_default_importer() == config.IMPORTER_SPRITEFRAMES_NAME else 1.0 + + +func _get_import_order(): + return 1 + + +func _get_import_options(_path, _i): + return [ + {"name": "layer/exclude_layers_pattern", "default_value": config.get_default_exclusion_pattern()}, + {"name": "layer/only_visible_layers", "default_value": false}, + { + "name": "sheet/sheet_type", + "default_value": "packed", + "property_hint": PROPERTY_HINT_ENUM, + "hint_string": "columns,horizontal,vertical,packed", + }, + { + "name": "sheet/sheet_columns", + "default_value": 12, + }, + {"name": "animation/round_fps", "default_value": true}, + ] + + +func _get_option_visibility(path, option, options): + return true + + +func _import(source_file, save_path, options, platform_variants, gen_files): + var absolute_source_file = ProjectSettings.globalize_path(source_file) + var absolute_save_path = ProjectSettings.globalize_path(save_path) + + var source_path = source_file.get_base_dir() + var source_basename = source_file.substr(source_path.length()+1, -1) + source_basename = source_basename.substr(0, source_basename.rfind('.')) + + var aseprite_opts = { + "export_mode": _sf_creator.FILE_EXPORT_MODE, + "exception_pattern": options['layer/exclude_layers_pattern'], + "only_visible_layers": options['layer/only_visible_layers'], + "output_filename": '', + "output_folder": source_path, + "sheet_type": options["sheet/sheet_type"], + "sheet_columns": options["sheet/sheet_columns"], + } + + var source_files = _aseprite_file_exporter.generate_aseprite_files(absolute_source_file, aseprite_opts) + if not source_files.is_ok: + printerr("ERROR - Could not import aseprite file: %s" % result_codes.get_error_message(source_files.code)) + return FAILED + + var resources = _sf_creator.create_resources(source_files.content, { + "should_round_fps": options["animation/round_fps"], + "should_create_portable_texture": true, + "sheet_base_path": save_path, + }) + + if not resources.is_ok: + printerr("ERROR - Could not import aseprite file: %s" % result_codes.get_error_message(resources.code)) + return FAILED + + var resource: Dictionary = resources.content[0] + resource.resource.set_meta("imported_via_aw", true) + var resource_path = "%s.res" % save_path + var exit_code = ResourceSaver.save(resource.resource, resource_path) + resource.resource.take_over_path(resource_path) + + #for extra_file in resource.extra_gen_files: + #gen_files.push_back(extra_file) + + if config.should_remove_source_files(): + _remove_source_files(source_files.content) + + if exit_code != OK: + printerr("ERROR - Could not persist aseprite file: %s" % result_codes.get_error_message(exit_code)) + return FAILED + + return OK + + +func _remove_source_files(source_files: Array): + for s in source_files: + DirAccess.remove_absolute(s.data_file) + DirAccess.remove_absolute(s.sprite_sheet) diff --git a/hexmapper/addons/AsepriteWizard/importers/sprite_frames_import_plugin.gd.uid b/hexmapper/addons/AsepriteWizard/importers/sprite_frames_import_plugin.gd.uid new file mode 100644 index 0000000..37a8d98 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/sprite_frames_import_plugin.gd.uid @@ -0,0 +1 @@ +uid://bffpek43i21it diff --git a/hexmapper/addons/AsepriteWizard/importers/sprite_frames_multiple_import_plugin.gd b/hexmapper/addons/AsepriteWizard/importers/sprite_frames_multiple_import_plugin.gd new file mode 100644 index 0000000..a0a84d9 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/sprite_frames_multiple_import_plugin.gd @@ -0,0 +1,49 @@ +@tool +extends "./multiple_import_plugin_base.gd" + + +func _get_importer_name(): + return "aseprite_wizard.plugin.spriteframes-split" + + +func _get_visible_name(): + return "Aseprite SpriteFrames (Split By Layer)" + + +func _get_priority(): + return 2.0 if config.get_default_importer() == config.IMPORTER_SPRITEFRAMES_SPLIT_NAME else 1.0 + + +func _get_import_options(_path, _i): + return [ + {"name": "layer/exclude_layers_pattern", "default_value": config.get_default_exclusion_pattern()}, + {"name": "layer/only_visible_layers", "default_value": false}, + { + "name": "sheet/sheet_type", + "default_value": "packed", + "property_hint": PROPERTY_HINT_ENUM, + "hint_string": "columns,horizontal,vertical,packed", + }, + { + "name": "sheet/sheet_columns", + "default_value": 12, + }, + {"name": "animation/round_fps", "default_value": true}, + { + "name": "output/layers_resources_folder", + "default_value": "", + "property_hint": PROPERTY_HINT_DIR, + } + ] + + +func _layer_extension() -> String: + return "ase_layer" + + +func _get_base_import_options(options: Dictionary): + return { + "sheet_type": options["sheet/sheet_type"], + "sheet_columns": options["sheet/sheet_columns"], + "should_round_fps": options["animation/round_fps"], + } diff --git a/hexmapper/addons/AsepriteWizard/importers/sprite_frames_multiple_import_plugin.gd.uid b/hexmapper/addons/AsepriteWizard/importers/sprite_frames_multiple_import_plugin.gd.uid new file mode 100644 index 0000000..a175e57 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/sprite_frames_multiple_import_plugin.gd.uid @@ -0,0 +1 @@ +uid://cet3t6bfaryhx diff --git a/hexmapper/addons/AsepriteWizard/importers/static_texture_import_plugin.gd b/hexmapper/addons/AsepriteWizard/importers/static_texture_import_plugin.gd new file mode 100644 index 0000000..c951ac0 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/static_texture_import_plugin.gd @@ -0,0 +1,54 @@ +@tool +extends "./static_texture_import_plugin_base.gd" + + +## +## Static texture importer. +## Imports first frame from Aseprite file as texture +## + +func _get_importer_name(): + return "aseprite_wizard.plugin.static-texture" + + +func _get_visible_name(): + return "Aseprite Texture" + + +func _get_recognized_extensions(): + return ["aseprite", "ase"] + + +func _get_priority(): + return 2.0 if config.get_default_importer() == config.IMPORTER_STATIC_TEXTURE_NAME else 0.8 + + +func _get_import_options(_path, _i): + return [ + {"name": "layer/exclude_layers_pattern", "default_value": config.get_default_exclusion_pattern()}, + {"name": "layer/only_visible_layers", "default_value": false}, + ] + + +func _import(source_file, save_path, options, platform_variants, gen_files): + var absolute_source_file = ProjectSettings.globalize_path(source_file) + var source_path = source_file.get_base_dir() + + var aseprite_opts = { + "exception_pattern": options['layer/exclude_layers_pattern'], + "only_visible_layers": options['layer/only_visible_layers'], + "output_filename": '', + "output_folder": source_path, + "first_frame_only": true, + } + + var result = _generate_texture(absolute_source_file, aseprite_opts) + + if not result.is_ok: + printerr("ERROR - Could not import aseprite file: %s" % result_codes.get_error_message(result.code)) + return FAILED + + var sprite_sheet = result.content.sprite_sheet + var data = result.content.data + + return _save_resource(sprite_sheet, save_path, result.content.data_file, data.meta.size) diff --git a/hexmapper/addons/AsepriteWizard/importers/static_texture_import_plugin.gd.uid b/hexmapper/addons/AsepriteWizard/importers/static_texture_import_plugin.gd.uid new file mode 100644 index 0000000..fc16f19 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/static_texture_import_plugin.gd.uid @@ -0,0 +1 @@ +uid://cgissgnbau7d5 diff --git a/hexmapper/addons/AsepriteWizard/importers/static_texture_import_plugin_base.gd b/hexmapper/addons/AsepriteWizard/importers/static_texture_import_plugin_base.gd new file mode 100644 index 0000000..8258dc4 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/static_texture_import_plugin_base.gd @@ -0,0 +1,71 @@ +@tool +extends EditorImportPlugin + +const result_codes = preload("../config/result_codes.gd") +var _aseprite_file_exporter = preload("../aseprite/file_exporter.gd").new() + +var config = preload("../config/config.gd").new() + + +func _get_save_extension(): + return "res" + + +func _get_resource_type(): + return "PortableCompressedTexture2D" + + +func _get_preset_count(): + return 1 + + +func _get_preset_name(i): + return "Default" + + +func _get_import_order(): + return 1 + + +func _get_option_visibility(path, option, options): + return true + + +func _generate_texture(absolute_source_file: String, options: Dictionary) -> Dictionary: + var result = _aseprite_file_exporter.generate_aseprite_file(absolute_source_file, options) + + if not result.is_ok: + return result + + var sprite_sheet = result.content.sprite_sheet + var data_result = _aseprite_file_exporter.load_json_content(result.content.data_file) + + if not data_result.is_ok: + return data_result + + var data = data_result.content + + return result_codes.result({ + "data_file": result.content.data_file, + "sprite_sheet": sprite_sheet, + "data": data + }) + + +func _save_resource(sprite_sheet: String, save_path: String, data_file_path: String, size: Dictionary) -> int: + var image = Image.load_from_file(sprite_sheet) + + var tex := PortableCompressedTexture2D.new() + tex.create_from_image(image, PortableCompressedTexture2D.COMPRESSION_MODE_LOSSLESS) +# + var exit_code = ResourceSaver.save(tex, "%s.%s" % [save_path, _get_save_extension()]) + + if config.should_remove_source_files(): + DirAccess.remove_absolute(data_file_path) + DirAccess.remove_absolute(sprite_sheet) + + if exit_code != OK: + printerr("ERROR - Could not persist aseprite file: %s" % result_codes.get_error_message(exit_code)) + return FAILED + + return OK diff --git a/hexmapper/addons/AsepriteWizard/importers/static_texture_import_plugin_base.gd.uid b/hexmapper/addons/AsepriteWizard/importers/static_texture_import_plugin_base.gd.uid new file mode 100644 index 0000000..d20018b --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/static_texture_import_plugin_base.gd.uid @@ -0,0 +1 @@ +uid://b1q5n3o01i5tv diff --git a/hexmapper/addons/AsepriteWizard/importers/static_texture_multiple_import_plugin.gd b/hexmapper/addons/AsepriteWizard/importers/static_texture_multiple_import_plugin.gd new file mode 100644 index 0000000..165aa69 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/static_texture_multiple_import_plugin.gd @@ -0,0 +1,34 @@ +@tool +extends "./multiple_import_plugin_base.gd" + + +func _get_importer_name(): + return "aseprite_wizard.plugin.static-texture-split" + + +func _get_visible_name(): + return "Aseprite Texture (Split By Layer)" + + +func _get_priority(): + return 2.0 if config.get_default_importer() == config.IMPORTER_STATIC_TEXTURE_SPLIT_NAME else 1.0 + + +func _get_import_options(_path, _i): + return [ + {"name": "layer/exclude_layers_pattern", "default_value": config.get_default_exclusion_pattern()}, + {"name": "layer/only_visible_layers", "default_value": false}, + { + "name": "output/layers_resources_folder", + "default_value": "", + "property_hint": PROPERTY_HINT_DIR, + } + ] + + +func _layer_extension() -> String: + return "ase_layer_tex" + + +func _get_base_import_options(options: Dictionary): + return {} diff --git a/hexmapper/addons/AsepriteWizard/importers/static_texture_multiple_import_plugin.gd.uid b/hexmapper/addons/AsepriteWizard/importers/static_texture_multiple_import_plugin.gd.uid new file mode 100644 index 0000000..7ed5783 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/static_texture_multiple_import_plugin.gd.uid @@ -0,0 +1 @@ +uid://slny0vb6r7j2 diff --git a/hexmapper/addons/AsepriteWizard/importers/tileset_texture_import_plugin.gd b/hexmapper/addons/AsepriteWizard/importers/tileset_texture_import_plugin.gd new file mode 100644 index 0000000..3ff62e4 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/tileset_texture_import_plugin.gd @@ -0,0 +1,138 @@ +@tool +extends EditorImportPlugin + +## +## Tileset texture importer. +## Imports Aseprite tileset layers as an AtlasTexture +## + +const result_codes = preload("../config/result_codes.gd") +var _aseprite_file_exporter = preload("../aseprite/file_exporter.gd").new() + +var config = preload("../config/config.gd").new() +var file_system: EditorFileSystem = EditorInterface.get_resource_filesystem() + + +func _get_importer_name(): + return "aseprite_wizard.plugin.tileset-texture" + + +func _get_visible_name(): + return "Aseprite Tileset Texture" + + +func _get_recognized_extensions(): + return ["aseprite", "ase"] + + +func _get_save_extension(): + return "res" + + +func _get_resource_type(): + return "PortableCompressedTexture2D" + + +func _get_preset_count(): + return 1 + + +func _get_preset_name(i): + return "Default" + + +func _get_priority(): + return 2.0 if config.get_default_importer() == config.IMPORTER_TILESET_TEXTURE_NAME else 0.9 + + +func _get_import_order(): + return 1 + + +func _get_import_options(_path, _i): + return [ + {"name": "layer/exclude_layers_pattern", "default_value": config.get_default_exclusion_pattern()}, + {"name": "layer/only_visible_layers", "default_value": false}, + { + "name": "sheet/sheet_type", + "default_value": "columns", + "property_hint": PROPERTY_HINT_ENUM, + "hint_string": "columns,horizontal,vertical,packed", + }, + { + "name": "sheet/sheet_columns", + "default_value": 12, + }, + ] + +func _get_option_visibility(path, option, options): + return true + + +func _import(source_file, save_path, options, platform_variants, gen_files): + var absolute_source_file = ProjectSettings.globalize_path(source_file) + var absolute_save_path = ProjectSettings.globalize_path(save_path) + var source_path = source_file.get_base_dir() + var source_basename = source_file.substr(source_path.length()+1, -1) + source_basename = source_basename.substr(0, source_basename.rfind('.')) + + var aseprite_opts = { + "exception_pattern": options['layer/exclude_layers_pattern'], + "only_visible_layers": options['layer/only_visible_layers'], + "output_filename": '', + "output_folder": source_path, + "sheet_type": options["sheet/sheet_type"], + "sheet_columns": options["sheet/sheet_columns"], + } + + var result = _generate_texture(absolute_source_file, aseprite_opts) + + if not result.is_ok: + printerr("ERROR - Could not import aseprite file: %s" % result_codes.get_error_message(result.code)) + return FAILED + + var sprite_sheet = result.content.sprite_sheet + var data = result.content.data + + return _save_resource(sprite_sheet, save_path, result.content.data_file, data.meta.size) + + +func _generate_texture(absolute_source_file: String, options: Dictionary) -> Dictionary: + var result = _aseprite_file_exporter.generate_tileset_files(absolute_source_file, options) + + if not result.is_ok: + return result + + var sprite_sheet = result.content.sprite_sheet + + var data_result = _aseprite_file_exporter.load_json_content(result.content.data_file) + + if not data_result.is_ok: + return data_result + + var data = data_result.content + + return result_codes.result({ + "data_file": result.content.data_file, + "sprite_sheet": sprite_sheet, + "data": data + }) + + +func _save_resource(sprite_sheet: String, save_path: String, data_file_path: String, size: Dictionary) -> int: + var image = Image.load_from_file(sprite_sheet) + + var tex := PortableCompressedTexture2D.new() + tex.create_from_image(image, PortableCompressedTexture2D.COMPRESSION_MODE_LOSSLESS) + + var exit_code = ResourceSaver.save(tex, "%s.%s" % [save_path, _get_save_extension()]) + + if config.should_remove_source_files(): + DirAccess.remove_absolute(data_file_path) + DirAccess.remove_absolute(sprite_sheet) + + if exit_code != OK: + printerr("ERROR - Could not persist aseprite file: %s" % result_codes.get_error_message(exit_code)) + return FAILED + + return OK diff --git a/hexmapper/addons/AsepriteWizard/importers/tileset_texture_import_plugin.gd.uid b/hexmapper/addons/AsepriteWizard/importers/tileset_texture_import_plugin.gd.uid new file mode 100644 index 0000000..d634881 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/importers/tileset_texture_import_plugin.gd.uid @@ -0,0 +1 @@ +uid://dao40mnmgx2u4 diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/animated_sprite/animated_sprite_inspector_dock.gd b/hexmapper/addons/AsepriteWizard/interface/docks/animated_sprite/animated_sprite_inspector_dock.gd new file mode 100644 index 0000000..c345f86 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/animated_sprite/animated_sprite_inspector_dock.gd @@ -0,0 +1,74 @@ +@tool +extends "../base_inspector_dock.gd" + +var sprite_frames_creator = preload("../../../creators/sprite_frames/sprite_frames_creator.gd").new() + +@onready var _animation_section := $dock_fields/VBoxContainer/extra/sections/animation_sf as VBoxContainer +@onready var _animation_section_header := $dock_fields/VBoxContainer/extra/sections/animation_sf/section_header as Button +@onready var _animation_section_container := $dock_fields/VBoxContainer/extra/sections/animation_sf/section_content as MarginContainer +@onready var _round_fps := $dock_fields/VBoxContainer/extra/sections/animation_sf/section_content/content/round_fps/CheckBox as CheckBox +const INTERFACE_SECTION_KEY_ANIMATION = "animation_section" + + +func _pre_setup(): + _expandable_sections[INTERFACE_SECTION_KEY_ANIMATION] = { "header": _animation_section_header, "content": _animation_section_container} + + +func _setup(): + _animation_section_header.button_down.connect(_on_animation_header_button_down) + + +func _load_config(cfg): + _round_fps.button_pressed = cfg.get("should_round_fps", true) + + +func _get_available_layers(global_source_path: String) -> Array: + return sprite_frames_creator.list_layers(global_source_path) + + +func _get_available_slices(global_source_path: String) -> Array: + return sprite_frames_creator.list_slices(global_source_path) + + +func _do_import(): + var root = get_tree().get_edited_scene_root() + + var source_path = ProjectSettings.globalize_path(_source) + var options = _get_import_options(root.scene_file_path.get_base_dir()) + + _save_config() + + var aseprite_output = _aseprite_file_exporter.generate_aseprite_file(source_path, options) + + if not aseprite_output.is_ok: + var error = result_code.get_error_message(aseprite_output.code) + printerr(error) + _show_message(error) + return + + file_system.scan() + await file_system.filesystem_changed + + sprite_frames_creator.create_animations(target_node, aseprite_output.content, { + "slice": _slice, + "should_round_fps": _round_fps.button_pressed, + "should_create_portable_texture": _embed_field.button_pressed, + }) + + wizard_config.set_source_hash(target_node, FileAccess.get_md5(source_path)) + + _handle_cleanup(aseprite_output.content, _embed_field.button_pressed) + + +func _show_specific_fields(): + _animation_section.show() + + +func _get_current_field_values() -> Dictionary: + return { + "should_round_fps": _round_fps.button_pressed, + } + + +func _on_animation_header_button_down(): + _toggle_section_visibility(INTERFACE_SECTION_KEY_ANIMATION) diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/animated_sprite/animated_sprite_inspector_dock.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/animated_sprite/animated_sprite_inspector_dock.gd.uid new file mode 100644 index 0000000..52d111b --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/animated_sprite/animated_sprite_inspector_dock.gd.uid @@ -0,0 +1 @@ +uid://dqftdv5pla1ax diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/animated_sprite/animated_sprite_inspector_dock.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/animated_sprite/animated_sprite_inspector_dock.tscn new file mode 100644 index 0000000..346c73c --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/animated_sprite/animated_sprite_inspector_dock.tscn @@ -0,0 +1,15 @@ +[gd_scene load_steps=3 format=3 uid="uid://vej7yqkbtd5f"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/docks/animated_sprite/animated_sprite_inspector_dock.gd" id="1"] +[ext_resource type="PackedScene" uid="uid://uxm7b02wry10" path="res://addons/AsepriteWizard/interface/docks/dock_fields.tscn" id="2_2ilip"] + +[node name="animated_sprite_inspector_dock" type="PanelContainer"] +offset_right = 14.0 +offset_bottom = 14.0 +script = ExtResource("1") + +[node name="dock_fields" parent="." instance=ExtResource("2_2ilip")] +layout_mode = 2 + +[connection signal="field_changed" from="dock_fields" to="." method="_on_dock_fields_field_changed"] +[connection signal="revert_changes_requested" from="dock_fields" to="." method="_on_dock_fields_revert_changes_requested"] diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/animated_sprite/inspector_plugin.gd b/hexmapper/addons/AsepriteWizard/interface/docks/animated_sprite/inspector_plugin.gd new file mode 100644 index 0000000..774a1cd --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/animated_sprite/inspector_plugin.gd @@ -0,0 +1,13 @@ +@tool +extends EditorInspectorPlugin + +const ASInspectorDock = preload("./animated_sprite_inspector_dock.tscn") + +func _can_handle(object): + return object is AnimatedSprite2D || object is AnimatedSprite3D + + +func _parse_end(object): + var dock = ASInspectorDock.instantiate() + dock.target_node = object + add_custom_control(dock) diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/animated_sprite/inspector_plugin.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/animated_sprite/inspector_plugin.gd.uid new file mode 100644 index 0000000..6480f84 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/animated_sprite/inspector_plugin.gd.uid @@ -0,0 +1 @@ +uid://boni725doa1qa diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/base_inspector_dock.gd b/hexmapper/addons/AsepriteWizard/interface/docks/base_inspector_dock.gd new file mode 100644 index 0000000..8fe8099 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/base_inspector_dock.gd @@ -0,0 +1,571 @@ +@tool +extends PanelContainer + +const wizard_config = preload("../../config/wizard_config.gd") +const result_code = preload("../../config/result_codes.gd") +var _aseprite_file_exporter = preload("../../aseprite/file_exporter.gd").new() +var config = preload("../../config/config.gd").new() + +var scene: Node +var target_node: Node +var file_system: EditorFileSystem = EditorInterface.get_resource_filesystem() + +var _slice: String = "" +var _source: String = "" +var _file_dialog_aseprite: EditorFileDialog +var _output_folder_dialog: EditorFileDialog +var _importing := false +var _output_folder := "" +var _out_folder_default := "[Same as scene]" +var _layer_default := "[all]" + +var _output_filename_text := "File Name" +var _output_filename_prefix_text := "File Name Prefix" + +var _interface_section_state + +@onready var _section_title := $dock_fields/VBoxContainer/title as Button + +# general +@onready var _source_field := $dock_fields/VBoxContainer/source/button as Button +# layers +@onready var _layer_section_header := $dock_fields/VBoxContainer/extra/sections/layers/section_header as Button +@onready var _layer_section_container := $dock_fields/VBoxContainer/extra/sections/layers/section_content as MarginContainer +@onready var _layer_field := $dock_fields/VBoxContainer/extra/sections/layers/section_content/content/layer/options as VBoxContainer +@onready var _visible_layers_field := $dock_fields/VBoxContainer/extra/sections/layers/section_content/content/visible_layers/CheckBox as CheckBox +@onready var _ex_pattern_field := $dock_fields/VBoxContainer/extra/sections/layers/section_content/content/ex_pattern/LineEdit as LineEdit +# slice +@onready var _slice_section_header := $dock_fields/VBoxContainer/extra/sections/slices/section_header as Button +@onready var _slice_section_container := $dock_fields/VBoxContainer/extra/sections/slices/section_content as MarginContainer +@onready var _slice_field := $dock_fields/VBoxContainer/extra/sections/slices/section_content/content/slice/options as OptionButton +# output +@onready var _output_section_header := $dock_fields/VBoxContainer/extra/sections/output/section_header as Button +@onready var _output_section_container := $dock_fields/VBoxContainer/extra/sections/output/section_content as MarginContainer +@onready var _out_folder_field := $dock_fields/VBoxContainer/extra/sections/output/section_content/content/out_folder/button as Button +@onready var _out_folder_container := $dock_fields/VBoxContainer/extra/sections/output/section_content/content/out_folder as HBoxContainer + +@onready var _out_filename_field := $dock_fields/VBoxContainer/extra/sections/output/section_content/content/out_filename/LineEdit as LineEdit +@onready var _out_filename_label := $dock_fields/VBoxContainer/extra/sections/output/section_content/content/out_filename/Label as Label +@onready var _out_filename_container := $dock_fields/VBoxContainer/extra/sections/output/section_content/content/out_filename as HBoxContainer + +@onready var _embed_label := $dock_fields/VBoxContainer/extra/sections/output/section_content/content/embed/Label as Label +@onready var _embed_field := $dock_fields/VBoxContainer/extra/sections/output/section_content/content/embed/CheckBox as CheckBox + +@onready var _import_button := $dock_fields/VBoxContainer/import as Button + +const INTERFACE_SECTION_KEY_LAYER = "layer_section" +const INTERFACE_SECTION_KEY_SLICE = "slice_section" +const INTERFACE_SECTION_KEY_OUTPUT = "output_section" + +@onready var _expandable_sections = { + INTERFACE_SECTION_KEY_LAYER: { "header": _layer_section_header, "content": _layer_section_container}, + INTERFACE_SECTION_KEY_SLICE: { "header": _slice_section_header, "content": _slice_section_container}, + INTERFACE_SECTION_KEY_OUTPUT: { "header": _output_section_header, "content": _output_section_container}, +} + +const PENDING_CHANGES_KEY := "pending_changes" + +var _do_not_update_pending := false + +func _ready(): + _pre_setup() + _setup_interface() + _setup_config() + _setup_field_listeners() + _setup() + _check_for_changes() + _check_for_field_changes() + + +func _check_for_changes(): + if not _source or _source == "": + return + + var saved_hash = wizard_config.get_source_hash(target_node) + + if saved_hash == "": + return + + if saved_hash != FileAccess.get_md5(_source): + $dock_fields.show_source_change_warning() + + +func _check_for_field_changes(): + var cfg = wizard_config.load_config(target_node) + var changed = _get_changed_config(cfg) + + if changed == null or changed.is_empty(): + $dock_fields.hide_fields_change_warning() + _interface_section_state[PENDING_CHANGES_KEY] = {} + else: + if cfg != null and not cfg.is_empty(): # has saved data + $dock_fields.show_fields_change_warning() + _interface_section_state[PENDING_CHANGES_KEY] = changed + + +func _update_pending_fields(): + if _do_not_update_pending: + return + + _check_for_field_changes() + wizard_config.save_interface_config(target_node, _interface_section_state) + + +func _get_changed_config(saved_config): + var current = _get_current_config() + + if saved_config == null: + return current if current != null else {} + + if current == null: + return {} + + var changed := {} + + for c in current: + if saved_config.get(c) != current[c]: + changed[c] = current[c] + + return changed + + +func _setup_interface(): + _hide_fields() + _show_specific_fields() + var cfg = wizard_config.load_interface_config(target_node) + _interface_section_state = cfg + + _section_title.add_theme_stylebox_override("normal", _section_title.get_theme_stylebox("hover")) + + for key in _expandable_sections: + _adjust_section_visibility(key) + + +func _load_persisted_config() -> Dictionary: + var cfg = wizard_config.load_config(target_node) + var persisted = {} + if cfg == null: + persisted = {} + else: + persisted = cfg.duplicate() + + var changed = _interface_section_state.get(PENDING_CHANGES_KEY, {}) + + for c in changed: + persisted[c] = changed[c] + + return persisted + + +func _setup_config(): + var cfg = _load_persisted_config() + + if cfg.is_empty(): + _load_common_default_config() + else: + _load_common_config(cfg) + + +func _load_common_config(cfg): + if cfg.has("source"): + _set_source(cfg.source) + + # keeping this to be backwards compatible + if cfg.get("layer", "") != "": + _layer_field.set_selected_layers([cfg.layer]) + _update_pending_fields() + _out_filename_label.text = _output_filename_prefix_text + else: + var layers = cfg.get("layers", []) + _layer_field.set_selected_layers(layers) + if layers.size() > 0: + _update_pending_fields() + if layers.size() == 1: + _out_filename_label.text = _output_filename_prefix_text + + if cfg.get("slice", "") != "": + _slice_field.clear() + _set_slice(cfg.slice) + else: + _slice = "" + _slice_field.select(0) + + _set_out_folder(cfg.get("o_folder", "")) + _out_filename_field.text = cfg.get("o_name", "") + _visible_layers_field.button_pressed = cfg.get("only_visible", false) + _ex_pattern_field.text = cfg.get("o_ex_p", "") + + _embed_field.button_pressed = cfg.get("embed_tex", false) + + _load_config(cfg) + _handle_embed_visibility() + + +func _load_common_default_config(): + _ex_pattern_field.text = config.get_default_exclusion_pattern() + _visible_layers_field.button_pressed = config.should_include_only_visible_layers_by_default() + #_cleanup_hide_unused_nodes.button_pressed = config.is_set_visible_track_automatically_enabled() + _load_default_config() + + +func _set_source(source): + _source = source + _source_field.text = _source + _source_field.tooltip_text = _source + _update_pending_fields() + + +func _set_slice(slice): + _slice = slice + _slice_field.add_item(_slice) + _update_pending_fields() + + +func _set_out_folder(path): + _output_folder = path + _out_folder_field.text = _output_folder if _output_folder != "" else _out_folder_default + _out_folder_field.tooltip_text = _out_folder_field.text + _update_pending_fields() + + +func _toggle_section_visibility(key: String) -> void: + _interface_section_state[key] = not _interface_section_state.get(key, false) + _adjust_section_visibility(key) + wizard_config.save_interface_config(target_node, _interface_section_state) + + +func _adjust_section_visibility(key: String) -> void: + var section = _expandable_sections[key] + var is_visible = _interface_section_state.get(key, false) + _adjust_icon(section.header, is_visible) + section.content.visible = is_visible + + +func _adjust_icon(section: Button, is_visible: bool = true) -> void: + var icon_name = "GuiTreeArrowDown" if is_visible else "GuiTreeArrowRight" + section.icon = get_theme_icon(icon_name, "EditorIcons") + + +func _setup_field_listeners(): + _layer_section_header.button_down.connect(_on_layer_header_button_down) + _slice_section_header.button_down.connect(_on_slice_header_button_down) + _output_section_header.button_down.connect(_on_output_header_button_down) + + _source_field.pressed.connect(_on_source_pressed) + _source_field.aseprite_file_dropped.connect(_on_source_aseprite_file_dropped) + + _layer_field.data_fetcher = _fetch_layers + _layer_field.value_changed.connect(_on_layer_value_changed) + + _slice_field.button_down.connect(_on_slice_button_down) + _slice_field.item_selected.connect(_on_slice_item_selected) + + _out_folder_field.dir_dropped.connect(_on_out_dir_dropped) + _out_folder_field.pressed.connect(_on_out_folder_pressed) + + _import_button.pressed.connect(_on_import_pressed) + + _embed_field.pressed.connect(_on_embed_button_pressed) + + +func _on_layer_header_button_down(): + _toggle_section_visibility(INTERFACE_SECTION_KEY_LAYER) + + +func _on_slice_header_button_down(): + _toggle_section_visibility(INTERFACE_SECTION_KEY_SLICE) + + +func _on_output_header_button_down(): + _toggle_section_visibility(INTERFACE_SECTION_KEY_OUTPUT) + + +func _fetch_layers(): + if _source == "": + _show_message("Please. Select source file first.") + return + + return _get_available_layers(ProjectSettings.globalize_path(_source)) + + +func _on_layer_value_changed(): + var layers: Array = _layer_field.get_selected_layers() + + if layers.size() == 1: + _out_filename_label.text = _output_filename_prefix_text + _update_pending_fields() + return + + _out_filename_label.text = _output_filename_text + _update_pending_fields() + + +func _on_slice_item_selected(index): + if index == 0: + _slice = "" + return + _slice = _slice_field.get_item_text(index) + _update_pending_fields() + + +func _on_slice_button_down(): + if _source == "": + _show_message("Please, select source file first.") + return + + var slices = _get_available_slices(ProjectSettings.globalize_path(_source)) + var current = 0 + _slice_field.clear() + _slice_field.add_item(_layer_default) + + for s in slices: + if s == "": + continue + + _slice_field.add_item(s) + if s == _slice: + current = _slice_field.get_item_count() - 1 + _slice_field.select(current) + + +func _on_source_pressed(): + _open_source_dialog() + + +func _get_current_config(): + var child_config = _get_current_field_values() + + var cfg := { + "source": _source, + "layers": _layer_field.get_selected_layers(), + "slice": _slice, + "o_folder": _output_folder, + "o_name": _out_filename_field.text, + "only_visible": _visible_layers_field.button_pressed, + "o_ex_p": _ex_pattern_field.text, + "embed_tex": _embed_field.button_pressed, + } + + for c in child_config: + cfg[c] = child_config[c] + + return cfg + + +## +## Save current import options to node metadata +## +func _save_config(): + wizard_config.save_config(target_node, _get_current_config()) + _update_pending_fields() + EditorInterface.mark_scene_as_unsaved() + + +func _get_import_options(default_folder: String): + return { + "output_folder": _output_folder if _output_folder != "" else default_folder, + "exception_pattern": _ex_pattern_field.text, + "only_visible_layers": _visible_layers_field.button_pressed, + "output_filename": _out_filename_field.text, + "layers": _layer_field.get_selected_layers(), + "embed_tex": _embed_field.button_pressed, + } + + +func _open_source_dialog(): + _file_dialog_aseprite = _create_aseprite_file_selection() + get_parent().add_child(_file_dialog_aseprite) + if _source != "": + _file_dialog_aseprite.current_dir = ProjectSettings.globalize_path(_source.get_base_dir()) + _file_dialog_aseprite.popup_centered_ratio() + + +func _create_aseprite_file_selection(): + var file_dialog = EditorFileDialog.new() + file_dialog.file_mode = EditorFileDialog.FILE_MODE_OPEN_FILE + file_dialog.access = EditorFileDialog.ACCESS_FILESYSTEM + file_dialog.connect("file_selected",Callable(self,"_on_aseprite_file_selected")) + file_dialog.set_filters(PackedStringArray(["*.ase","*.aseprite"])) + return file_dialog + + +func _on_aseprite_file_selected(path): + _set_source(ProjectSettings.localize_path(path)) + _update_pending_fields() + _file_dialog_aseprite.queue_free() + + +func _on_source_aseprite_file_dropped(path): + _set_source(path) + _update_pending_fields() + + +## Helper method to populate field with values +func _populate_options_field(field: OptionButton, values: Array, current_name: String): + var current = 0 + field.clear() + field.add_item("[all]") + + for v in values: + if v == "": + continue + + field.add_item(v) + if v == current_name: + current = field.get_item_count() - 1 + field.select(current) + + +func _on_out_folder_pressed(): + _output_folder_dialog = _create_output_folder_selection() + get_parent().add_child(_output_folder_dialog) + if _output_folder != _out_folder_default: + _output_folder_dialog.current_dir = _output_folder + _output_folder_dialog.popup_centered_ratio() + + +func _create_output_folder_selection(): + var file_dialog = EditorFileDialog.new() + file_dialog.file_mode = EditorFileDialog.FILE_MODE_OPEN_DIR + file_dialog.access = EditorFileDialog.ACCESS_RESOURCES + file_dialog.connect("dir_selected",Callable(self,"_on_output_folder_selected")) + return file_dialog + + +func _on_output_folder_selected(path): + _set_out_folder(path) + _output_folder_dialog.queue_free() + _update_pending_fields() + + +func _on_out_dir_dropped(path): + _set_out_folder(path) + _update_pending_fields() + + +func _on_embed_button_pressed(): + _handle_embed_visibility() + + +func _handle_embed_visibility(): + if _embed_field.button_pressed: + _out_folder_container.hide() + _out_filename_container.hide() + else: + _out_folder_container.show() + _out_filename_container.show() + + +func _show_message(message: String): + var _warning_dialog = AcceptDialog.new() + get_parent().add_child(_warning_dialog) + _warning_dialog.dialog_text = message + _warning_dialog.popup_centered() + _warning_dialog.canceled.connect(_warning_dialog.queue_free) + _warning_dialog.confirmed.connect(_warning_dialog.queue_free) + + +func _notify_aseprite_error(aseprite_error_code): + var error = result_code.get_error_message(aseprite_error_code) + printerr(error) + _show_message(error) + + +func _handle_cleanup(aseprite_content, should_remove_spritesheet = false): + if config.should_remove_source_files(): + DirAccess.remove_absolute(aseprite_content.data_file) + if should_remove_spritesheet: + DirAccess.remove_absolute(aseprite_content.sprite_sheet) + var import_file = "%s.import" % aseprite_content.sprite_sheet + if FileAccess.file_exists(import_file): + DirAccess.remove_absolute(import_file) + + file_system.call_deferred("scan") + + +func _on_import_pressed(): + if _importing: + return + _importing = true + + if _source == "": + _show_message("Aseprite file not selected") + _importing = false + return + + if get_tree().get_edited_scene_root().scene_file_path == "": + _show_message("Scene needs to be saved at least once before importing animations") + _importing = false + return + + await _do_import() + _importing = false + $dock_fields.hide_source_change_warning() + EditorInterface.save_scene() + + + +# This is a little bit leaky as this base scene contains fields only relevant to animation players. +# However, this is the simplest thing I can do without overcomplicating stuff. +func _hide_fields(): + $dock_fields/VBoxContainer/modes.hide() + $dock_fields/VBoxContainer/animation_player.hide() + $dock_fields/VBoxContainer/extra/sections/animation.hide() + $dock_fields/VBoxContainer/extra/sections/animation_sf.hide() + + +func _on_dock_fields_revert_changes_requested() -> void: + $dock_fields.disable_change_notification = true + _do_not_update_pending = true + _interface_section_state[PENDING_CHANGES_KEY] = {} + wizard_config.save_interface_config(target_node, _interface_section_state) + _setup_config() + $dock_fields.disable_change_notification = false + $dock_fields.hide_fields_change_warning() + _do_not_update_pending = false + EditorInterface.mark_scene_as_unsaved() + + +func _on_dock_fields_field_changed() -> void: + _check_for_field_changes() + + +## this will be called before base class does its setup +func _pre_setup(): + pass + + +## this will be called after base class setup is complete +func _setup(): + pass + + +func _load_default_config(): + pass + + +func _load_config(cfg: Dictionary): + pass + + +## Override to return available layers +func _get_available_layers(global_source_path: String) -> Array: + return [] + + +## Override to return available slices +func _get_available_slices(global_source_path: String) -> Array: + return [] + + +## Override this method for extra import options to add to node metadata +func _get_current_field_values() -> Dictionary: + return {} + + +func _do_import(): + pass + + +func _show_specific_fields() -> void: + pass diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/base_inspector_dock.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/base_inspector_dock.gd.uid new file mode 100644 index 0000000..b0eb028 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/base_inspector_dock.gd.uid @@ -0,0 +1 @@ +uid://di76ywq167ex6 diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/dock_fields.gd b/hexmapper/addons/AsepriteWizard/interface/docks/dock_fields.gd new file mode 100644 index 0000000..201ae3c --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/dock_fields.gd @@ -0,0 +1,85 @@ +@tool +extends MarginContainer + +signal revert_changes_requested +signal field_changed + +@onready +var _source_changed_warning_container = $VBoxContainer/source_changed_warning +@onready +var _source_changed_warning_icon = $VBoxContainer/source_changed_warning/MarginContainer/HBoxContainer/Icon + +@onready +var _fields_changed_warning_container = $VBoxContainer/fields_changed_warning +@onready +var _fields_changed_warning_icon = $VBoxContainer/fields_changed_warning/MarginContainer/VBoxContainer/HBoxContainer/Icon + +var disable_change_notification := false + +func _ready(): + var sb = _source_changed_warning_container.get_theme_stylebox("panel") + var color = EditorInterface.get_editor_settings().get_setting("interface/theme/accent_color") + color.a = 0.2 + sb.bg_color = color + + _source_changed_warning_icon.texture = get_theme_icon("NodeInfo", "EditorIcons") + _fields_changed_warning_icon.texture = get_theme_icon("NodeInfo", "EditorIcons") + hide_source_change_warning() + hide_fields_change_warning() + + +func show_source_change_warning(): + _source_changed_warning_container.show() + + +func hide_source_change_warning(): + _source_changed_warning_container.hide() + + +func show_fields_change_warning(): + _fields_changed_warning_container.show() + + +func hide_fields_change_warning(): + _fields_changed_warning_container.hide() + + +func _on_revert_changes_button_up() -> void: + revert_changes_requested.emit() + + +func _on_ex_pattern_text_changed(_new_text: String) -> void: + _notify_change_with_debounce() + + +func _on_visible_layer_toggled(_toggled_on: bool) -> void: + _notify_change_with_debounce() + + +func _on_keep_length_toggled(_toggled_on: bool) -> void: + _notify_change_with_debounce() + + +func _on_anim_vis_toggled(_toggled_on: bool) -> void: + _notify_change_with_debounce() + + +func _on_line_edit_text_changed(_new_text: String) -> void: + _notify_change_with_debounce() + + +func _on_debounce_timer_timeout() -> void: + if not $DebounceTimer.is_stopped(): + $DebounceTimer.stop() + $DebounceTimer.start() + + +func _notify_change_with_debounce(): + if disable_change_notification: + return + + field_changed.emit() + + +func _on_round_fps_toggled(_toggled_on: bool) -> void: + _notify_change_with_debounce() diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/dock_fields.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/dock_fields.gd.uid new file mode 100644 index 0000000..7a3a459 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/dock_fields.gd.uid @@ -0,0 +1 @@ +uid://ddg74nfct8wf6 diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/dock_fields.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/dock_fields.tscn new file mode 100644 index 0000000..f0feedb --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/dock_fields.tscn @@ -0,0 +1,469 @@ +[gd_scene load_steps=12 format=3 uid="uid://uxm7b02wry10"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/docks/dock_fields.gd" id="1_f3w00"] +[ext_resource type="PackedScene" uid="uid://x1f1t87m582u" path="res://addons/AsepriteWizard/interface/shared/animation_player_drop_button.tscn" id="1_gh7xg"] +[ext_resource type="PackedScene" uid="uid://dj1uo3blocr8e" path="res://addons/AsepriteWizard/interface/shared/source_drop_button.tscn" id="1_y4qrm"] +[ext_resource type="PackedScene" uid="uid://cwvgnm3o7eed2" path="res://addons/AsepriteWizard/interface/shared/dir_drop_button.tscn" id="2_pypqg"] +[ext_resource type="PackedScene" uid="uid://ddlr2qc0atcfm" path="res://addons/AsepriteWizard/interface/docks/multi_layer_select_field.tscn" id="4_1c7t4"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ptlkd"] +content_margin_left = 4.0 +content_margin_top = 4.0 +content_margin_right = 4.0 +content_margin_bottom = 4.0 +bg_color = Color(0.225, 0.225, 0.225, 0.6) +corner_radius_top_left = 3 +corner_radius_top_right = 3 +corner_radius_bottom_right = 3 +corner_radius_bottom_left = 3 +corner_detail = 5 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gu58o"] +bg_color = Color(0.53, 0.67, 0.89, 0.2) +border_width_left = 10 +border_color = Color(0.8, 0.8, 0.8, 0) +corner_radius_top_left = 5 +corner_radius_top_right = 5 +corner_radius_bottom_right = 5 +corner_radius_bottom_left = 5 + +[sub_resource type="Image" id="Image_r8qc8"] +data = { +"data": PackedByteArray(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, 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, 94, 94, 127, 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, 94, 94, 127, 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, 94, 94, 127, 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, 255, 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, 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, 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, 94, 94, 54, 255, 94, 94, 57, 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, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 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, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 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, 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, 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_wd1ne"] +image = SubResource("Image_r8qc8") + +[sub_resource type="Image" id="Image_mnqfn"] +data = { +"data": PackedByteArray(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, 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, 94, 94, 127, 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, 94, 94, 127, 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, 94, 94, 127, 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, 255, 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, 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, 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, 94, 94, 54, 255, 94, 94, 57, 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, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 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, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 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, 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, 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_qqpl1"] +image = SubResource("Image_mnqfn") + +[node name="dock_fields" type="MarginContainer"] +script = ExtResource("1_f3w00") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 + +[node name="title" type="Button" parent="VBoxContainer"] +layout_mode = 2 +focus_mode = 0 +theme_override_styles/normal = SubResource("StyleBoxFlat_ptlkd") +button_mask = 0 +text = "Aseprite" + +[node name="fields_changed_warning" type="PanelContainer" parent="VBoxContainer"] +visible = false +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_gu58o") + +[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/fields_changed_warning"] +layout_mode = 2 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_right = 10 + +[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/fields_changed_warning/MarginContainer"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/fields_changed_warning/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="Icon" type="TextureRect" parent="VBoxContainer/fields_changed_warning/MarginContainer/VBoxContainer/HBoxContainer"] +modulate = Color(1, 1, 1, 0.486275) +custom_minimum_size = Vector2(16, 0) +layout_mode = 2 +texture = SubResource("ImageTexture_wd1ne") +stretch_mode = 5 + +[node name="Label" type="Label" parent="VBoxContainer/fields_changed_warning/MarginContainer/VBoxContainer/HBoxContainer"] +custom_minimum_size = Vector2(10, 0) +layout_mode = 2 +size_flags_horizontal = 3 +text = "Configuration changed since last import" +autowrap_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/fields_changed_warning/MarginContainer/VBoxContainer"] +layout_mode = 2 +theme_override_constants/margin_bottom = 4 + +[node name="Button" type="Button" parent="VBoxContainer/fields_changed_warning/MarginContainer/VBoxContainer/MarginContainer"] +layout_mode = 2 +size_flags_horizontal = 8 +text = "Revert Changes" + +[node name="section_title" type="PanelContainer" parent="VBoxContainer"] +visible = false +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/section_title"] +layout_mode = 2 +alignment = 1 + +[node name="icon" type="TextureRect" parent="VBoxContainer/section_title/HBoxContainer"] +custom_minimum_size = Vector2(16, 16) +layout_mode = 2 + +[node name="title" type="Label" parent="VBoxContainer/section_title/HBoxContainer"] +layout_mode = 2 +text = "Aseprite" +horizontal_alignment = 1 + +[node name="modes" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +tooltip_text = "Import mode. +Animation mode (default): set spritesheet as texture and imports animations to the selected AnimationPlayer. +Image mode: Import only first frame and set as texture." + +[node name="Label" type="Label" parent="VBoxContainer/modes"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "Mode" + +[node name="options" type="OptionButton" parent="VBoxContainer/modes"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +selected = 0 +item_count = 2 +popup/item_0/text = "Animation" +popup/item_1/text = "Image" +popup/item_1/id = 1 + +[node name="animation_player" type="HBoxContainer" parent="VBoxContainer" groups=["aw_animation_player_only"]] +layout_mode = 2 +tooltip_text = "AnimationPlayer node where animations should be added to." + +[node name="Label" type="Label" parent="VBoxContainer/animation_player"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "AnimationPlayer" + +[node name="options" parent="VBoxContainer/animation_player" instance=ExtResource("1_gh7xg")] +layout_mode = 2 + +[node name="source" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +tooltip_text = "Location of the Aseprite (*.ase, *.aseprite) source file." + +[node name="Label" type="Label" parent="VBoxContainer/source"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "Aseprite File" + +[node name="button" parent="VBoxContainer/source" instance=ExtResource("1_y4qrm")] +layout_mode = 2 + +[node name="source_changed_warning" type="PanelContainer" parent="VBoxContainer"] +visible = false +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_gu58o") + +[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/source_changed_warning"] +layout_mode = 2 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_right = 10 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/source_changed_warning/MarginContainer"] +layout_mode = 2 + +[node name="Icon" type="TextureRect" parent="VBoxContainer/source_changed_warning/MarginContainer/HBoxContainer"] +modulate = Color(1, 1, 1, 0.486275) +custom_minimum_size = Vector2(16, 0) +layout_mode = 2 +texture = SubResource("ImageTexture_wd1ne") +stretch_mode = 5 + +[node name="Label" type="Label" parent="VBoxContainer/source_changed_warning/MarginContainer/HBoxContainer"] +custom_minimum_size = Vector2(10, 0) +layout_mode = 2 +size_flags_horizontal = 3 +text = "Source file changed since last import" +autowrap_mode = 2 + +[node name="extra" type="MarginContainer" parent="VBoxContainer"] +layout_mode = 2 +theme_override_constants/margin_left = 10 + +[node name="sections" type="VBoxContainer" parent="VBoxContainer/extra"] +layout_mode = 2 + +[node name="layers" type="VBoxContainer" parent="VBoxContainer/extra/sections"] +layout_mode = 2 + +[node name="section_header" type="Button" parent="VBoxContainer/extra/sections/layers"] +layout_mode = 2 +focus_mode = 0 +text = "Layers" +icon = SubResource("ImageTexture_qqpl1") +alignment = 0 + +[node name="section_content" type="MarginContainer" parent="VBoxContainer/extra/sections/layers"] +visible = false +layout_mode = 2 +theme_override_constants/margin_left = 10 + +[node name="content" type="VBoxContainer" parent="VBoxContainer/extra/sections/layers/section_content"] +layout_mode = 2 + +[node name="layer" type="HBoxContainer" parent="VBoxContainer/extra/sections/layers/section_content/content"] +layout_mode = 2 +tooltip_text = "Aseprite layer to be used in the animation. By default all layers are included." + +[node name="Label" type="Label" parent="VBoxContainer/extra/sections/layers/section_content/content/layer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "Layer" + +[node name="options" parent="VBoxContainer/extra/sections/layers/section_content/content/layer" instance=ExtResource("4_1c7t4")] +layout_mode = 2 + +[node name="ex_pattern" type="HBoxContainer" parent="VBoxContainer/extra/sections/layers/section_content/content"] +layout_mode = 2 +tooltip_text = "Exclude layers with name matching this pattern (regex)." + +[node name="Label" type="Label" parent="VBoxContainer/extra/sections/layers/section_content/content/ex_pattern"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "Exclude Pattern" + +[node name="LineEdit" type="LineEdit" parent="VBoxContainer/extra/sections/layers/section_content/content/ex_pattern"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 + +[node name="visible_layers" type="HBoxContainer" parent="VBoxContainer/extra/sections/layers/section_content/content"] +layout_mode = 2 +tooltip_text = "If active, layers not visible in the source file won't be included in the final image." + +[node name="Label" type="Label" parent="VBoxContainer/extra/sections/layers/section_content/content/visible_layers"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "Only Visible Layers" + +[node name="CheckBox" type="CheckBox" parent="VBoxContainer/extra/sections/layers/section_content/content/visible_layers"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "On" + +[node name="slices" type="VBoxContainer" parent="VBoxContainer/extra/sections"] +layout_mode = 2 + +[node name="section_header" type="Button" parent="VBoxContainer/extra/sections/slices"] +layout_mode = 2 +focus_mode = 0 +text = "Slices" +icon = SubResource("ImageTexture_qqpl1") +alignment = 0 + +[node name="section_content" type="MarginContainer" parent="VBoxContainer/extra/sections/slices"] +visible = false +layout_mode = 2 +theme_override_constants/margin_left = 10 + +[node name="content" type="VBoxContainer" parent="VBoxContainer/extra/sections/slices/section_content"] +layout_mode = 2 + +[node name="slice" type="HBoxContainer" parent="VBoxContainer/extra/sections/slices/section_content/content"] +layout_mode = 2 +tooltip_text = "Aseprite slice to be used in the animation. By default, the whole file is included." + +[node name="Label" type="Label" parent="VBoxContainer/extra/sections/slices/section_content/content/slice"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "Slice" + +[node name="options" type="OptionButton" parent="VBoxContainer/extra/sections/slices/section_content/content/slice"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +selected = 0 +item_count = 1 +popup/item_0/text = "[all]" + +[node name="animation" type="VBoxContainer" parent="VBoxContainer/extra/sections" groups=["aw_animation_player_only"]] +layout_mode = 2 + +[node name="section_header" type="Button" parent="VBoxContainer/extra/sections/animation"] +layout_mode = 2 +focus_mode = 0 +text = "Animation" +icon = SubResource("ImageTexture_qqpl1") +alignment = 0 + +[node name="section_content" type="MarginContainer" parent="VBoxContainer/extra/sections/animation"] +visible = false +layout_mode = 2 +theme_override_constants/margin_left = 10 + +[node name="content" type="VBoxContainer" parent="VBoxContainer/extra/sections/animation/section_content"] +layout_mode = 2 + +[node name="keep_length" type="HBoxContainer" parent="VBoxContainer/extra/sections/animation/section_content/content"] +layout_mode = 2 +tooltip_text = "When this is active the animation length won't be adjusted if other properties were added and the resulting imported animation is shorter." + +[node name="Label" type="Label" parent="VBoxContainer/extra/sections/animation/section_content/content/keep_length"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "Keep Manual Animation Length" + +[node name="CheckBox" type="CheckBox" parent="VBoxContainer/extra/sections/animation/section_content/content/keep_length"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "On" + +[node name="auto_visible_track" type="HBoxContainer" parent="VBoxContainer/extra/sections/animation/section_content/content"] +layout_mode = 2 +tooltip_text = "If active on import, this node will be set as hidden in every existing animation it is not part of" + +[node name="Label" type="Label" parent="VBoxContainer/extra/sections/animation/section_content/content/auto_visible_track"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "Hide When Unused" + +[node name="CheckBox" type="CheckBox" parent="VBoxContainer/extra/sections/animation/section_content/content/auto_visible_track"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "On" + +[node name="animation_sf" type="VBoxContainer" parent="VBoxContainer/extra/sections"] +layout_mode = 2 + +[node name="section_header" type="Button" parent="VBoxContainer/extra/sections/animation_sf"] +layout_mode = 2 +focus_mode = 0 +text = "Animation" +icon = SubResource("ImageTexture_qqpl1") +alignment = 0 + +[node name="section_content" type="MarginContainer" parent="VBoxContainer/extra/sections/animation_sf"] +layout_mode = 2 +theme_override_constants/margin_left = 10 + +[node name="content" type="VBoxContainer" parent="VBoxContainer/extra/sections/animation_sf/section_content"] +layout_mode = 2 + +[node name="round_fps" type="HBoxContainer" parent="VBoxContainer/extra/sections/animation_sf/section_content/content"] +layout_mode = 2 +tooltip_text = "Round FPS to the next integer number." + +[node name="Label" type="Label" parent="VBoxContainer/extra/sections/animation_sf/section_content/content/round_fps"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "Round FPS" + +[node name="CheckBox" type="CheckBox" parent="VBoxContainer/extra/sections/animation_sf/section_content/content/round_fps"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +button_pressed = true +text = "On" + +[node name="output" type="VBoxContainer" parent="VBoxContainer/extra/sections"] +layout_mode = 2 + +[node name="section_header" type="Button" parent="VBoxContainer/extra/sections/output"] +layout_mode = 2 +focus_mode = 0 +text = "Output" +icon = SubResource("ImageTexture_qqpl1") +alignment = 0 + +[node name="section_content" type="MarginContainer" parent="VBoxContainer/extra/sections/output"] +visible = false +layout_mode = 2 +theme_override_constants/margin_left = 10 + +[node name="content" type="VBoxContainer" parent="VBoxContainer/extra/sections/output/section_content"] +layout_mode = 2 + +[node name="embed" type="HBoxContainer" parent="VBoxContainer/extra/sections/output/section_content/content"] +layout_mode = 2 +tooltip_text = "Embed texture in the SpriteFrames instead of creating an external file" + +[node name="Label" type="Label" parent="VBoxContainer/extra/sections/output/section_content/content/embed"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "Embed Texture" + +[node name="CheckBox" type="CheckBox" parent="VBoxContainer/extra/sections/output/section_content/content/embed"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +button_pressed = true +text = "On" + +[node name="out_folder" type="HBoxContainer" parent="VBoxContainer/extra/sections/output/section_content/content"] +visible = false +layout_mode = 2 +tooltip_text = "Location where the spritesheet file should be saved." + +[node name="Label" type="Label" parent="VBoxContainer/extra/sections/output/section_content/content/out_folder"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "Folder" + +[node name="button" parent="VBoxContainer/extra/sections/output/section_content/content/out_folder" instance=ExtResource("2_pypqg")] +layout_mode = 2 + +[node name="out_filename" type="HBoxContainer" parent="VBoxContainer/extra/sections/output/section_content/content"] +visible = false +layout_mode = 2 +tooltip_text = "Base filename for spritesheet. In case the layer option is used, this works as a prefix to the layer name." + +[node name="Label" type="Label" parent="VBoxContainer/extra/sections/output/section_content/content/out_filename"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "File Name" + +[node name="LineEdit" type="LineEdit" parent="VBoxContainer/extra/sections/output/section_content/content/out_filename"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 + +[node name="import" type="Button" parent="VBoxContainer"] +layout_mode = 2 +text = "Import" + +[node name="DebounceTimer" type="Timer" parent="."] +wait_time = 0.6 +one_shot = true + +[connection signal="button_up" from="VBoxContainer/fields_changed_warning/MarginContainer/VBoxContainer/MarginContainer/Button" to="." method="_on_revert_changes_button_up"] +[connection signal="text_changed" from="VBoxContainer/extra/sections/layers/section_content/content/ex_pattern/LineEdit" to="." method="_on_ex_pattern_text_changed"] +[connection signal="toggled" from="VBoxContainer/extra/sections/layers/section_content/content/visible_layers/CheckBox" to="." method="_on_visible_layer_toggled"] +[connection signal="toggled" from="VBoxContainer/extra/sections/animation/section_content/content/keep_length/CheckBox" to="." method="_on_keep_length_toggled"] +[connection signal="toggled" from="VBoxContainer/extra/sections/animation/section_content/content/auto_visible_track/CheckBox" to="." method="_on_anim_vis_toggled"] +[connection signal="toggled" from="VBoxContainer/extra/sections/animation_sf/section_content/content/round_fps/CheckBox" to="." method="_on_round_fps_toggled"] +[connection signal="toggled" from="VBoxContainer/extra/sections/output/section_content/content/embed/CheckBox" to="." method="_on_round_fps_toggled"] +[connection signal="text_changed" from="VBoxContainer/extra/sections/output/section_content/content/out_filename/LineEdit" to="." method="_on_line_edit_text_changed"] +[connection signal="timeout" from="DebounceTimer" to="." method="_on_debounce_timer_timeout"] diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/layer_select_field.gd b/hexmapper/addons/AsepriteWizard/interface/docks/layer_select_field.gd new file mode 100644 index 0000000..d203070 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/layer_select_field.gd @@ -0,0 +1,81 @@ +@tool +extends HBoxContainer + +signal add_pressed +signal removed_pressed +signal data_requested +signal value_changed(value: String) + +var _value: String = "" +var is_only_field := false + +func _ready(): + $add_btn.icon = get_theme_icon("Add", "EditorIcons") + $remove_btn.icon = get_theme_icon("Remove", "EditorIcons") + +func set_add_button(visibility: bool) -> void: + $add_btn.visible = visibility + + +func set_remove_button(visibility: bool) -> void: + $remove_btn.visible = visibility + + +func _on_remove_btn_pressed() -> void: + removed_pressed.emit() + + +func _on_add_btn_pressed() -> void: + add_pressed.emit() + + +func _on_options_button_down() -> void: + data_requested.emit() + + +func _on_options_item_selected(index: int) -> void: + if index == 0: + _value = "" + else: + _value = $options.get_item_text(index) + + value_changed.emit(_value) + + +func populate_field(option_values): + var current = 0 + $options.clear() + set_default_item() + + for v in option_values: + if v == "": + continue + + $options.add_item(v) + if v == _value: + current = $options.get_item_count() - 1 + $options.select(current) + + +func set_value(new_value: String) -> void: + _value = new_value + $options.clear() + + if new_value == "": + set_default_item() + else: + $options.add_item(_value) + + +func get_value(): + return _value + + +func clear_options(): + $options.clear() + set_default_item() + $options.select(0) + + +func set_default_item(): + $options.add_item("[all]" if is_only_field else "Select layer...") diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/layer_select_field.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/layer_select_field.gd.uid new file mode 100644 index 0000000..1ea55ca --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/layer_select_field.gd.uid @@ -0,0 +1 @@ +uid://v3yh7cuspy4f diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/layer_select_field.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/layer_select_field.tscn new file mode 100644 index 0000000..b869e75 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/layer_select_field.tscn @@ -0,0 +1,43 @@ +[gd_scene load_steps=4 format=3 uid="uid://b8ricawxf4kxs"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/docks/layer_select_field.gd" id="1_6ya8h"] + +[sub_resource type="Image" id="Image_g7kfe"] +data = { +"data": PackedByteArray(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, 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, 94, 94, 127, 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, 94, 94, 127, 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, 94, 94, 127, 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, 255, 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, 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, 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, 94, 94, 54, 255, 94, 94, 57, 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, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 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, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 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, 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, 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_t5qui"] +image = SubResource("Image_g7kfe") + +[node name="layer_fields" type="HBoxContainer"] +script = ExtResource("1_6ya8h") + +[node name="options" type="OptionButton" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +selected = 0 +item_count = 1 +popup/item_0/text = "[all]" + +[node name="add_btn" type="Button" parent="."] +visible = false +layout_mode = 2 +tooltip_text = "Add another layer" +icon = SubResource("ImageTexture_t5qui") + +[node name="remove_btn" type="Button" parent="."] +visible = false +layout_mode = 2 +tooltip_text = "Remove layer" +icon = SubResource("ImageTexture_t5qui") + +[connection signal="button_down" from="options" to="." method="_on_options_button_down"] +[connection signal="item_selected" from="options" to="." method="_on_options_item_selected"] +[connection signal="pressed" from="add_btn" to="." method="_on_add_btn_pressed"] +[connection signal="pressed" from="remove_btn" to="." method="_on_remove_btn_pressed"] diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/multi_layer_select_field.gd b/hexmapper/addons/AsepriteWizard/interface/docks/multi_layer_select_field.gd new file mode 100644 index 0000000..8ba00e0 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/multi_layer_select_field.gd @@ -0,0 +1,116 @@ +@tool +extends VBoxContainer + +const LayerField = preload("./layer_select_field.tscn") + +signal value_changed + +var data_fetcher: Callable + +func set_selected_layers(layers: Array): + for c in get_children(): + c.queue_free() + + if layers.size() > 1: + var last + for layer in layers: + var field = LayerField.instantiate() + field.set_remove_button(true) + add_child(field) + field.set_value(layer) + _hook_signals(field) + last = field + last.set_add_button(true) + return + + var field = LayerField.instantiate() + field.is_only_field = true + add_child(field) + + if layers.is_empty(): + field.set_value("") + else: + field.set_value(layers[0]) + field.set_add_button(true) + _hook_signals(field) + + +func get_selected_layers() -> Array: + return _get_field_values() + + +func _get_field_values() -> Array: + var values = [] + + for c in get_children(): + var v = c.get_value() + if v != "" and not values.has(v): + values.push_back(v) + + return values + + +func _hook_signals(field: Control): + field.add_pressed.connect(_on_add_pressed.bind(field)) + field.removed_pressed.connect(_on_removed_pressed.bind(field)) + field.data_requested.connect(_on_data_requested.bind(field)) + field.value_changed.connect(_on_value_changed.bind(field)) + + +func _on_add_pressed(field: Control) -> void: + field.is_only_field = false + field.set_add_button(false) + field.set_remove_button(true) + + var new_field = LayerField.instantiate() + add_child(new_field) + new_field.set_add_button(true) + new_field.set_remove_button(true) + new_field.clear_options() + + _hook_signals(new_field) + + +func _on_removed_pressed(field: Control) -> void: + var count := get_child_count() + var node_position := field.get_index() + var should_notify_change: bool = field.get_value() != "" + + remove_child(field) + field.queue_free() + + if should_notify_change: + value_changed.emit() + + if count == 2: + for c in get_children(): + if c != field: + var last_node = c + last_node.set_add_button(true) + last_node.set_remove_button(false) + last_node.is_only_field = true + elif (count - 1) == node_position: + get_child(count - 2).set_add_button(true) + + +func _on_data_requested(field: Control) -> void: + var layers = data_fetcher.call() + + if layers == null: + return + + var selected_layers = get_selected_layers() + + var valid_values := [] + + for l in layers: + if not selected_layers.has(l) or l == field.get_value(): + valid_values.push_back(l) + + field.populate_field(valid_values) + + +func _on_value_changed(value: String, field: Control) -> void: + if value != "" and field.get_index() == get_child_count() - 1: + field.set_add_button(true) + value_changed.emit() diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/multi_layer_select_field.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/multi_layer_select_field.gd.uid new file mode 100644 index 0000000..ca87095 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/multi_layer_select_field.gd.uid @@ -0,0 +1 @@ +uid://bh0x5rm6qj0me diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/multi_layer_select_field.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/multi_layer_select_field.tscn new file mode 100644 index 0000000..2bb6acc --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/multi_layer_select_field.tscn @@ -0,0 +1,13 @@ +[gd_scene load_steps=3 format=3 uid="uid://ddlr2qc0atcfm"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/docks/multi_layer_select_field.gd" id="1_h2oy5"] +[ext_resource type="PackedScene" uid="uid://b8ricawxf4kxs" path="res://addons/AsepriteWizard/interface/docks/layer_select_field.tscn" id="2_75fqs"] + +[node name="layer_multiselect" type="VBoxContainer"] +offset_right = 40.0 +offset_bottom = 40.0 +size_flags_horizontal = 3 +script = ExtResource("1_h2oy5") + +[node name="layer_fields" parent="." instance=ExtResource("2_75fqs")] +layout_mode = 2 diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/sprite/inspector_plugin.gd b/hexmapper/addons/AsepriteWizard/interface/docks/sprite/inspector_plugin.gd new file mode 100644 index 0000000..ff3d617 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/sprite/inspector_plugin.gd @@ -0,0 +1,14 @@ +@tool +extends EditorInspectorPlugin + +const APInspectorDock = preload("./sprite_inspector_dock.tscn") + + +func _can_handle(object): + return object is Sprite2D || object is Sprite3D || object is TextureRect + + +func _parse_end(object): + var dock = APInspectorDock.instantiate() + dock.target_node = object + add_custom_control(dock) diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/sprite/inspector_plugin.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/sprite/inspector_plugin.gd.uid new file mode 100644 index 0000000..f60c0c6 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/sprite/inspector_plugin.gd.uid @@ -0,0 +1 @@ +uid://bq8chpgknl5ii diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/sprite/sprite_inspector_dock.gd b/hexmapper/addons/AsepriteWizard/interface/docks/sprite/sprite_inspector_dock.gd new file mode 100644 index 0000000..941d4e1 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/sprite/sprite_inspector_dock.gd @@ -0,0 +1,262 @@ +@tool +extends "../base_inspector_dock.gd" + +const AnimationCreator = preload("../../../creators/animation_player/animation_creator.gd") +const SpriteAnimationCreator = preload("../../../creators/animation_player/sprite_animation_creator.gd") +const TextureRectAnimationCreator = preload("../../../creators/animation_player/texture_rect_animation_creator.gd") +const StaticTextureCreator = preload("../../../creators/static_texture/texture_creator.gd") + +enum ImportMode { + ANIMATION = 0, + IMAGE = 1 +} + +var animation_creator: AnimationCreator +var static_texture_creator: StaticTextureCreator + +var _import_mode = -1 +var _animation_player_path: String + +@onready var _import_mode_options_field := $dock_fields/VBoxContainer/modes/options as OptionButton +@onready var _animation_player_field := $dock_fields/VBoxContainer/animation_player/options as OptionButton +@onready var _animation_player_container := $dock_fields/VBoxContainer/animation_player as HBoxContainer + +# animation +@onready var _animation_section := $dock_fields/VBoxContainer/extra/sections/animation as VBoxContainer +@onready var _animation_section_header := $dock_fields/VBoxContainer/extra/sections/animation/section_header as Button +@onready var _animation_section_container := $dock_fields/VBoxContainer/extra/sections/animation/section_content as MarginContainer +@onready var _cleanup_hide_unused_nodes := $dock_fields/VBoxContainer/extra/sections/animation/section_content/content/auto_visible_track/CheckBox as CheckBox +@onready var _keep_length := $dock_fields/VBoxContainer/extra/sections/animation/section_content/content/keep_length/CheckBox as CheckBox + +const INTERFACE_SECTION_KEY_ANIMATION = "animation_section" + + +func _pre_setup(): + _expandable_sections[INTERFACE_SECTION_KEY_ANIMATION] = { "header": _animation_section_header, "content": _animation_section_container} + + +func _setup(): + if target_node is Sprite2D || target_node is Sprite3D: + animation_creator = SpriteAnimationCreator.new() + if target_node is TextureRect: + animation_creator = TextureRectAnimationCreator.new() + + static_texture_creator = StaticTextureCreator.new() + + _setup_animation_fields_listeners() + + +func _load_config(cfg): + if cfg.has("player"): + _animation_player_field.clear() + _set_animation_player(cfg.player) + + _cleanup_hide_unused_nodes.button_pressed = cfg.get("set_vis_track", config.is_set_visible_track_automatically_enabled()) + _keep_length.button_pressed = cfg.get("keep_anim_length", false) + _set_import_mode(int(cfg.get("i_mode", 0))) + + +func _load_default_config(): + _cleanup_hide_unused_nodes.button_pressed = config.is_set_visible_track_automatically_enabled() + _set_import_mode(0) + + +func _set_animation_player(player): + _animation_player_path = player + _animation_player_field.add_item(_animation_player_path) + + +func _set_import_mode(import_mode): + if _import_mode == import_mode: + return + + _import_mode = import_mode + var index = _import_mode_options_field.get_item_index(import_mode) + _import_mode_options_field.select(index) + _handle_import_mode() + + +func _handle_import_mode(): + match _import_mode: + ImportMode.ANIMATION: + _animation_player_container.show() + _animation_section.show() + ImportMode.IMAGE: + _animation_player_container.hide() + _animation_section.hide() + + +func _setup_animation_fields_listeners(): + _animation_section_header.button_down.connect(_on_animation_header_button_down) + _animation_player_field.node_dropped.connect(_on_animation_player_node_dropped) + _animation_player_field.button_down.connect(_on_animation_player_button_down) + _animation_player_field.item_selected.connect(_on_animation_player_item_selected) + + _import_mode_options_field.item_selected.connect(_on_modes_item_selected) + + +func _on_animation_player_button_down(): + _refresh_animation_players() + + +func _refresh_animation_players(): + var animation_players = [] + var root = get_tree().get_edited_scene_root() + _find_animation_players(root, root, animation_players) + + var current = 0 + _animation_player_field.clear() + _animation_player_field.add_item("[empty]") + + for ap in animation_players: + _animation_player_field.add_item(ap) + if ap.get_concatenated_names() == _animation_player_path: + current = _animation_player_field.get_item_count() - 1 + + _animation_player_field.select(current) + + +func _find_animation_players(root: Node, node: Node, players: Array): + if node is AnimationPlayer: + players.push_back(root.get_path_to(node)) + + for c in node.get_children(): + _find_animation_players(root, c, players) + + +func _on_animation_player_item_selected(index): + if index == 0: + _animation_player_path = "" + return + _animation_player_path = _animation_player_field.get_item_text(index) + #_save_config() + _update_pending_fields() + + +func _do_import(): + if _import_mode == ImportMode.IMAGE: + await _import_static() + return + + await _import_for_animation_player() + +## +## Import aseprite animations to target AnimationPlayer and set +## spritesheet as the node's texture +## +func _import_for_animation_player(): + var root = get_tree().get_edited_scene_root() + + if _animation_player_path == "" or not root.has_node(_animation_player_path): + _show_message("AnimationPlayer not found") + _importing = false + return + + var source_path = ProjectSettings.globalize_path(_source) + + var options = _get_import_options(root.scene_file_path.get_base_dir()) + + _save_config() + + var aseprite_output = _aseprite_file_exporter.generate_aseprite_file(source_path, options) + + if not aseprite_output.is_ok: + _notify_aseprite_error(aseprite_output.code) + return + + file_system.scan() + await file_system.filesystem_changed + + var anim_options = { + "keep_anim_length": _keep_length.button_pressed, + "cleanup_hide_unused_nodes": _cleanup_hide_unused_nodes.button_pressed, + "slice": _slice, + "should_create_portable_texture": _embed_field.button_pressed, + } + + animation_creator.create_animations(target_node, root.get_node(_animation_player_path), aseprite_output.content, anim_options) + _importing = false + + wizard_config.set_source_hash(target_node, FileAccess.get_md5(source_path)) + _handle_cleanup(aseprite_output.content, _embed_field.button_pressed) + +## +## Import first frame from aseprite file as node texture +## +func _import_static(): + var source_path = ProjectSettings.globalize_path(_source) + var root = get_tree().get_edited_scene_root() + + var options = _get_import_options(root.scene_file_path.get_base_dir()) + options["first_frame_only"] = true + + _save_config() + + var aseprite_output = _aseprite_file_exporter.generate_aseprite_file(source_path, options) + + if not aseprite_output.is_ok: + _notify_aseprite_error(aseprite_output.code) + return + + file_system.scan() + await file_system.filesystem_changed + + static_texture_creator.load_texture(target_node, aseprite_output.content, { + "slice": _slice, + "should_create_portable_texture": _embed_field.button_pressed, + }) + + _importing = false + wizard_config.set_source_hash(target_node, FileAccess.get_md5(source_path)) + _handle_cleanup(aseprite_output.content, _embed_field.button_pressed) + + +func _get_current_field_values() -> Dictionary: + var cfg := { + "i_mode": _import_mode, + "player": _animation_player_path, + "keep_anim_length": _keep_length.button_pressed, + } + + if _cleanup_hide_unused_nodes.button_pressed != config.is_set_visible_track_automatically_enabled(): + cfg["set_vis_track"] = _cleanup_hide_unused_nodes.button_pressed + + return cfg + + +func _get_available_layers(global_source_path: String) -> Array: + return animation_creator.list_layers(global_source_path) + + +func _get_available_slices(global_source_path: String) -> Array: + return animation_creator.list_slices(global_source_path) + + +func _on_animation_player_node_dropped(node_path): + var node = get_node(node_path) + var root = get_tree().get_edited_scene_root() + + _animation_player_path = root.get_path_to(node) + + for i in range(_animation_player_field.get_item_count()): + if _animation_player_field.get_item_text(i) == _animation_player_path: + _animation_player_field.select(i) + break + #_save_config() + _update_pending_fields() + + +func _on_modes_item_selected(index): + var id = _import_mode_options_field.get_item_id(index) + _import_mode = id + _handle_import_mode() + + +func _on_animation_header_button_down(): + _toggle_section_visibility(INTERFACE_SECTION_KEY_ANIMATION) + + +func _show_specific_fields(): + _import_mode_options_field.get_parent().show() + _animation_player_container.show() + _animation_section.show() diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/sprite/sprite_inspector_dock.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/sprite/sprite_inspector_dock.gd.uid new file mode 100644 index 0000000..0f6c1b7 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/sprite/sprite_inspector_dock.gd.uid @@ -0,0 +1 @@ +uid://d7s0sepqaskq diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/sprite/sprite_inspector_dock.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/sprite/sprite_inspector_dock.tscn new file mode 100644 index 0000000..9adea11 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/sprite/sprite_inspector_dock.tscn @@ -0,0 +1,15 @@ +[gd_scene load_steps=3 format=3 uid="uid://biyshalfalqqw"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/docks/sprite/sprite_inspector_dock.gd" id="1_ku6wj"] +[ext_resource type="PackedScene" uid="uid://uxm7b02wry10" path="res://addons/AsepriteWizard/interface/docks/dock_fields.tscn" id="2_wkqx4"] + +[node name="sprite_inspector_dock" type="PanelContainer"] +offset_right = 14.0 +offset_bottom = 14.0 +script = ExtResource("1_ku6wj") + +[node name="dock_fields" parent="." instance=ExtResource("2_wkqx4")] +layout_mode = 2 + +[connection signal="field_changed" from="dock_fields" to="." method="_on_dock_fields_field_changed"] +[connection signal="revert_changes_requested" from="dock_fields" to="." method="_on_dock_fields_revert_changes_requested"] diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_dock_container.gd b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_dock_container.gd new file mode 100644 index 0000000..8b62224 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_dock_container.gd @@ -0,0 +1,39 @@ +@tool +extends TabContainer + +signal close_requested + +const WizardWindow = preload("./as_wizard_window.tscn") + +func _ready(): + $Import.close_requested.connect(emit_signal.bind("close_requested")) + $Import.import_success.connect(_on_import_success) + $History.request_edit.connect(_on_edit_request) + $History.request_import.connect(_on_import_request) + $ImportedSpriteFrames.import_success.connect($History.add_entry) + + self.set_tab_title(1, "Imported Resources") + + +func _on_AsWizardDockContainer_tab_changed(tab: int): + match tab: + 1: + $ImportedSpriteFrames.init_resources() + 2: + $History.reload() + + +func _on_edit_request(import_cfg: Dictionary): + $Import.load_import_config(import_cfg) + self.current_tab = 0 + + +func _on_import_request(import_cfg: Dictionary): + $Import.load_import_config(import_cfg) + $Import.trigger_import() + + +func _on_import_success(settings: Dictionary): + $ImportedSpriteFrames.init_resources() + $ImportedSpriteFrames.reload_tree() + $History.add_entry(settings) diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_dock_container.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_dock_container.gd.uid new file mode 100644 index 0000000..be61f61 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_dock_container.gd.uid @@ -0,0 +1 @@ +uid://ds73e5bh5alse diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_dock_container.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_dock_container.tscn new file mode 100644 index 0000000..9201fdb --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_dock_container.tscn @@ -0,0 +1,28 @@ +[gd_scene load_steps=5 format=3 uid="uid://b844j1tk3vxer"] + +[ext_resource type="PackedScene" uid="uid://c5dwobjd34w3p" path="res://addons/AsepriteWizard/interface/docks/wizard/as_wizard_window.tscn" id="1"] +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/docks/wizard/as_wizard_dock_container.gd" id="2"] +[ext_resource type="PackedScene" uid="uid://cyoin5ncul0fm" path="res://addons/AsepriteWizard/interface/docks/wizard/sprite_frames_import_history.tscn" id="3"] +[ext_resource type="PackedScene" uid="uid://bfhsdslj8kt7b" path="res://addons/AsepriteWizard/interface/docks/wizard/imported_sprite_frames.tscn" id="3_25qb4"] + +[node name="AsWizardDockContainer" type="TabContainer"] +offset_right = 281.0 +offset_bottom = 36.0 +tab_alignment = 2 +use_hidden_tabs_for_min_size = true +script = ExtResource("2") + +[node name="Import" parent="." instance=ExtResource("1")] +layout_mode = 2 +tooltip_text = "SpriteFrames Importer" + +[node name="ImportedSpriteFrames" parent="." instance=ExtResource("3_25qb4")] +visible = false +layout_mode = 2 +metadata/_tab_name = "Imported Resources" + +[node name="History" parent="." instance=ExtResource("3")] +visible = false +layout_mode = 2 + +[connection signal="tab_changed" from="." to="." method="_on_AsWizardDockContainer_tab_changed"] diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_window.gd b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_window.gd new file mode 100644 index 0000000..8041dff --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_window.gd @@ -0,0 +1,288 @@ +@tool +extends PanelContainer + +signal close_requested +signal import_success(file_settings) + +const result_code = preload("../../../config/result_codes.gd") +var _config = preload("../../../config/config.gd").new() + +var _import_helper = preload("./wizard_import_helper.gd").new() + +var _file_system: EditorFileSystem = EditorInterface.get_resource_filesystem() + +var _file_dialog_aseprite: EditorFileDialog +var _output_folder_dialog: EditorFileDialog +var _warning_dialog: AcceptDialog + +@onready var _layer_section_btn: Button = $container/options/layer_section/header/section_header +@onready var _layer_section_content: MarginContainer = $container/options/layer_section/section_content + +@onready var _animation_section_btn: Button = $container/options/animation_section/header/section_header +@onready var _animation_section_content: MarginContainer = $container/options/animation_section/section_content + +@onready var _output_section_btn: Button = $container/options/output_section/header/section_header +@onready var _output_section_content: MarginContainer = $container/options/output_section/section_content + +@onready var _file_location_field: LineEdit = $container/options/file_location/HBoxContainer/file_location_path + +@onready var _output_folder_field: LineEdit = $container/options/output_section/section_content/items/output_folder/HBoxContainer/file_location_path + +@onready var _exception_pattern_field: LineEdit = $container/options/layer_section/section_content/items/exclude_pattern/pattern + +@onready var _split_mode_field: CheckBox = $container/options/layer_section/section_content/items/split_layers/field + +@onready var _only_visible_layers_field: CheckBox = $container/options/layer_section/section_content/items/visible_layers/field + +@onready var _custom_name_field: LineEdit = $container/options/output_section/section_content/items/custom_filename/pattern + +@onready var _round_fps_field: CheckBox = $container/options/animation_section/section_content/items/round_fps/field + +@onready var _do_not_create_res_field: CheckBox = $container/options/output_section/section_content/items/disable_resource_creation/field + +const INTERFACE_SECTION_KEY_LAYER = "layer_section" +const INTERFACE_SECTION_KEY_ANIMATION = "animation_section" +const INTERFACE_SECTION_KEY_OUTPUT = "output_section" + +@onready var _expandable_sections = { + INTERFACE_SECTION_KEY_LAYER: { "header": _layer_section_btn, "content": _layer_section_content}, + INTERFACE_SECTION_KEY_ANIMATION: { "header": _animation_section_btn, "content": _animation_section_content}, + INTERFACE_SECTION_KEY_OUTPUT: { "header": _output_section_btn, "content": _output_section_content}, +} + +var _interface_section_state = {} + + +func _ready(): + _configure_sections() + _load_persisted_config() + + +func _exit_tree(): + if is_instance_valid(_file_dialog_aseprite): + _file_dialog_aseprite.queue_free() + if is_instance_valid(_output_folder_dialog): + _output_folder_dialog.queue_free() + if is_instance_valid(_warning_dialog): + _warning_dialog.queue_free() + + +func _init_aseprite_file_selection_dialog(): + _file_dialog_aseprite = _create_aseprite_file_selection() + get_parent().get_parent().add_child(_file_dialog_aseprite) + + +func _init_output_folder_selection_dialog(): + _output_folder_dialog = _create_outuput_folder_selection() + get_parent().get_parent().add_child(_output_folder_dialog) + + +func _init_warning_dialog(): + _warning_dialog = AcceptDialog.new() + _warning_dialog.exclusive = false + get_parent().get_parent().add_child(_warning_dialog) + + +func _load_persisted_config() -> void: + var cfg = _load_last_import_cfg() + _load_config(cfg) + + +func _load_config(cfg: Dictionary) -> void: + _split_mode_field.button_pressed = cfg.split_layers + _only_visible_layers_field.button_pressed = cfg.only_visible_layers + _exception_pattern_field.text = cfg.layer_exclusion_pattern + _custom_name_field.text = cfg.output_name + _file_location_field.text = cfg.source_file + _do_not_create_res_field.button_pressed = cfg.do_not_create_resource + _round_fps_field.button_pressed = cfg.get("should_round_fps", true) + _output_folder_field.text = cfg.output_location if cfg.output_location != "" else "res://" + + +func _save_config() -> void: + _config.set_standalone_spriteframes_last_import_config(_get_field_values()) + + +func _get_field_values() -> Dictionary: + return { + "split_layers": _split_mode_field.button_pressed, + "only_visible_layers": _only_visible_layers_field.button_pressed, + "layer_exclusion_pattern": _exception_pattern_field.text, + "output_name": _custom_name_field.text, + "source_file": _file_location_field.text, + "do_not_create_resource": _do_not_create_res_field.button_pressed, + "output_location": _output_folder_field.text if _output_folder_field.text != "" else "res://", + "should_round_fps": _round_fps_field.button_pressed, + } + + +func _clear_config() -> void: + _config.clear_standalone_spriteframes_last_import_config() + var default = _get_default_config() + _load_config(default) + + +## This is used by the other tabs to set the form fields +func load_import_config(field_values: Dictionary): + _split_mode_field.button_pressed = field_values.split_layers + _only_visible_layers_field.button_pressed = field_values.only_visible_layers + _exception_pattern_field.text = field_values.layer_exclusion_pattern + _custom_name_field.text = field_values.output_name + _file_location_field.text = field_values.source_file + _do_not_create_res_field.button_pressed = field_values.do_not_create_resource + _output_folder_field.text = field_values.output_location + _round_fps_field.button_pressed = field_values.get("should_round_fps", true) + + +func _open_aseprite_file_selection_dialog(): + if not is_instance_valid(_file_dialog_aseprite): + _init_aseprite_file_selection_dialog() + + var current_selection = _file_location_field.text + if current_selection != "": + _file_dialog_aseprite.current_dir = current_selection.get_base_dir() + _file_dialog_aseprite.popup_centered_ratio() + + +func _open_output_folder_selection_dialog(): + if not is_instance_valid(_output_folder_dialog): + _init_output_folder_selection_dialog() + var current_selection = _output_folder_field.text + if current_selection != "": + _output_folder_dialog.current_dir = current_selection + _output_folder_dialog.popup_centered_ratio() + + +func _create_aseprite_file_selection(): + var file_dialog = EditorFileDialog.new() + file_dialog.file_mode = EditorFileDialog.FILE_MODE_OPEN_FILE + file_dialog.access = EditorFileDialog.ACCESS_FILESYSTEM + file_dialog.connect("file_selected", _on_aseprite_file_selected) + file_dialog.set_filters(PackedStringArray(["*.ase","*.aseprite"])) + return file_dialog + + +func _create_outuput_folder_selection(): + var file_dialog = EditorFileDialog.new() + file_dialog.file_mode = EditorFileDialog.FILE_MODE_OPEN_DIR + file_dialog.access = EditorFileDialog.ACCESS_RESOURCES + file_dialog.connect("dir_selected", _on_output_folder_selected) + return file_dialog + + +func _on_aseprite_file_selected(path): + var localized_path = ProjectSettings.localize_path(path) + _file_location_field.text = localized_path + + +func _on_output_folder_selected(path): + _output_folder_field.text = path + + +func _on_next_btn_up(): + var aseprite_file = _file_location_field.text + var fields = _get_field_values() + var exit_code = await _import_helper.import_and_create_resources(aseprite_file, _get_field_values()) + + if exit_code != OK: + _show_error(exit_code) + return + + emit_signal("import_success", fields) + + if _config.should_remove_source_files(): + _file_system.call_deferred("scan") + + _show_import_success_message() + + +func trigger_import(): + _on_next_btn_up() + + +func _on_close_btn_up(): + _close_window() + + +func _close_window(): + _save_config() + self.emit_signal("close_requested") + + +func _on_clear_button_up(): + _clear_config() + + +func _show_error(code: int): + _show_error_message(result_code.get_error_message(code)) + + +func _show_error_message(message: String): + if not is_instance_valid(_warning_dialog): + _init_warning_dialog() + _warning_dialog.dialog_text = "Error: %s" % message + _warning_dialog.popup_centered() + + +func _show_import_success_message(): + if not is_instance_valid(_warning_dialog): + _init_warning_dialog() + _warning_dialog.dialog_text = "Aseprite import succeeded" + _warning_dialog.popup_centered() + _save_config() + + +func _configure_sections(): + for key in _expandable_sections: + _adjust_section_visibility(key) + + +func _adjust_section_visibility(key: String) -> void: + var section = _expandable_sections[key] + var is_visible = _interface_section_state.get(key, true) + _adjust_icon(section.header, is_visible) + section.content.visible = is_visible + + +func _adjust_icon(section: Button, is_visible: bool = true) -> void: + var icon_name = "GuiTreeArrowDown" if is_visible else "GuiTreeArrowRight" + section.icon = get_theme_icon(icon_name, "EditorIcons") + + +func _toggle_section_visibility(key: String) -> void: + _interface_section_state[key] = not _interface_section_state.get(key, true) + _adjust_section_visibility(key) + + +func _on_layer_section_header_button_down(): + _toggle_section_visibility(INTERFACE_SECTION_KEY_LAYER) + + +func _on_output_section_header_button_down(): + _toggle_section_visibility(INTERFACE_SECTION_KEY_OUTPUT) + + +func _on_animation_header_button_down() -> void: + _toggle_section_visibility(INTERFACE_SECTION_KEY_ANIMATION) + + +func _load_last_import_cfg() -> Dictionary: + var cfg = _config.get_standalone_spriteframes_last_import_config() + + if cfg.is_empty(): + return _get_default_config() + + return cfg + + +func _get_default_config() -> Dictionary: + return { + "split_layers": false, + "only_visible_layers": _config.should_include_only_visible_layers_by_default(), + "layer_exclusion_pattern": _config.get_default_exclusion_pattern(), + "output_name": "", + "source_file": "", + "do_not_create_resource": false, + "output_location": "res://", + "should_round_fps": true, + } diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_window.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_window.gd.uid new file mode 100644 index 0000000..1ba5c71 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_window.gd.uid @@ -0,0 +1 @@ +uid://b7fmruj4lfcae diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_window.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_window.tscn new file mode 100644 index 0000000..abb3a8b --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/as_wizard_window.tscn @@ -0,0 +1,233 @@ +[gd_scene load_steps=4 format=3 uid="uid://c5dwobjd34w3p"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/docks/wizard/as_wizard_window.gd" id="1"] + +[sub_resource type="Image" id="Image_1ofm5"] +data = { +"data": PackedByteArray(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, 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, 94, 94, 127, 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, 94, 94, 127, 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, 94, 94, 127, 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, 255, 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, 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, 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, 94, 94, 54, 255, 94, 94, 57, 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, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 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, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 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, 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, 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_r01jd"] +image = SubResource("Image_1ofm5") + +[node name="ASWizardWindow" type="PanelContainer"] +offset_right = 600.0 +offset_bottom = 600.0 +size_flags_horizontal = 3 +size_flags_vertical = 0 +script = ExtResource("1") + +[node name="container" type="MarginContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="options" type="VBoxContainer" parent="container"] +layout_mode = 2 +theme_override_constants/separation = 15 + +[node name="file_location" type="VBoxContainer" parent="container/options"] +layout_mode = 2 + +[node name="file_location_label" type="Label" parent="container/options/file_location"] +layout_mode = 2 +tooltip_text = "Location of the Aseprite *.ase source file" +mouse_filter = 1 +text = "Aseprite File Location:" +clip_text = true + +[node name="HBoxContainer" type="HBoxContainer" parent="container/options/file_location"] +layout_mode = 2 + +[node name="file_location_path" type="LineEdit" parent="container/options/file_location/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "res://test/llama_import.aseprite" +caret_blink = true + +[node name="file_location_btn" type="Button" parent="container/options/file_location/HBoxContainer"] +layout_mode = 2 +text = "Select" + +[node name="layer_section" type="VBoxContainer" parent="container/options"] +layout_mode = 2 + +[node name="header" type="HBoxContainer" parent="container/options/layer_section"] +layout_mode = 2 + +[node name="section_header" type="Button" parent="container/options/layer_section/header"] +layout_mode = 2 +text = "Layers" +icon = SubResource("ImageTexture_r01jd") +flat = true +alignment = 0 + +[node name="HSeparator" type="HSeparator" parent="container/options/layer_section/header"] +visible = false +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="section_content" type="MarginContainer" parent="container/options/layer_section"] +layout_mode = 2 +theme_override_constants/margin_left = 20 + +[node name="items" type="VBoxContainer" parent="container/options/layer_section/section_content"] +layout_mode = 2 + +[node name="exclude_pattern" type="VBoxContainer" parent="container/options/layer_section/section_content/items"] +layout_mode = 2 + +[node name="label" type="Label" parent="container/options/layer_section/section_content/items/exclude_pattern"] +layout_mode = 2 +tooltip_text = "If layer name matches this pattern, it won't be exported." +mouse_filter = 1 +text = "Exclude layers with name matching pattern:" + +[node name="pattern" type="LineEdit" parent="container/options/layer_section/section_content/items/exclude_pattern"] +layout_mode = 2 +text = "_$" +caret_blink = true + +[node name="split_layers" type="HBoxContainer" parent="container/options/layer_section/section_content/items"] +layout_mode = 2 + +[node name="field" type="CheckBox" parent="container/options/layer_section/section_content/items/split_layers"] +layout_mode = 2 +tooltip_text = "If selected, one resource will be created for each layer. +If not selected, layers will be merged and exported as one SpriteSheet." +text = "Split layers in multiple resources" + +[node name="visible_layers" type="HBoxContainer" parent="container/options/layer_section/section_content/items"] +layout_mode = 2 + +[node name="field" type="CheckBox" parent="container/options/layer_section/section_content/items/visible_layers"] +layout_mode = 2 +tooltip_text = "If selected, layers not visible in the source file won't be included in the final image." +text = "Only include visible layers" + +[node name="animation_section" type="VBoxContainer" parent="container/options"] +layout_mode = 2 + +[node name="header" type="HBoxContainer" parent="container/options/animation_section"] +layout_mode = 2 + +[node name="section_header" type="Button" parent="container/options/animation_section/header"] +layout_mode = 2 +text = "Animation" +icon = SubResource("ImageTexture_r01jd") +flat = true +alignment = 0 + +[node name="section_content" type="MarginContainer" parent="container/options/animation_section"] +layout_mode = 2 +theme_override_constants/margin_left = 20 + +[node name="items" type="VBoxContainer" parent="container/options/animation_section/section_content"] +layout_mode = 2 + +[node name="round_fps" type="HBoxContainer" parent="container/options/animation_section/section_content/items"] +layout_mode = 2 + +[node name="field" type="CheckBox" parent="container/options/animation_section/section_content/items/round_fps"] +layout_mode = 2 +tooltip_text = "If selected, rounds FPS to next integer" +button_pressed = true +text = "Round FPS" + +[node name="output_section" type="VBoxContainer" parent="container/options"] +layout_mode = 2 + +[node name="header" type="HBoxContainer" parent="container/options/output_section"] +layout_mode = 2 + +[node name="section_header" type="Button" parent="container/options/output_section/header"] +layout_mode = 2 +text = "Output" +icon = SubResource("ImageTexture_r01jd") +flat = true +alignment = 0 + +[node name="HSeparator" type="HSeparator" parent="container/options/output_section/header"] +visible = false +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="section_content" type="MarginContainer" parent="container/options/output_section"] +layout_mode = 2 +theme_override_constants/margin_left = 20 + +[node name="items" type="VBoxContainer" parent="container/options/output_section/section_content"] +layout_mode = 2 + +[node name="output_folder" type="VBoxContainer" parent="container/options/output_section/section_content/items"] +layout_mode = 2 + +[node name="label" type="Label" parent="container/options/output_section/section_content/items/output_folder"] +layout_mode = 2 +tooltip_text = "Folder where the SpriteSheet resource is going to be saved" +mouse_filter = 1 +text = "Output Folder:" + +[node name="HBoxContainer" type="HBoxContainer" parent="container/options/output_section/section_content/items/output_folder"] +layout_mode = 2 + +[node name="file_location_path" type="LineEdit" parent="container/options/output_section/section_content/items/output_folder/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "res://" +caret_blink = true + +[node name="output_folder_btn" type="Button" parent="container/options/output_section/section_content/items/output_folder/HBoxContainer"] +layout_mode = 2 +text = "Select" + +[node name="custom_filename" type="VBoxContainer" parent="container/options/output_section/section_content/items"] +layout_mode = 2 + +[node name="label" type="Label" parent="container/options/output_section/section_content/items/custom_filename"] +layout_mode = 2 +tooltip_text = "Output filename. In case layers are not being merged, this is used as file prefix. +If not set, source filename is used." +mouse_filter = 1 +text = "Output File Name / Prefix:" + +[node name="pattern" type="LineEdit" parent="container/options/output_section/section_content/items/custom_filename"] +layout_mode = 2 +caret_blink = true + +[node name="disable_resource_creation" type="HBoxContainer" parent="container/options/output_section/section_content/items"] +layout_mode = 2 + +[node name="field" type="CheckBox" parent="container/options/output_section/section_content/items/disable_resource_creation"] +layout_mode = 2 +tooltip_text = "Does not create SpriteFrames resource. Useful if you are only interested in the .json and .png output from Aseprite." +text = "Do not create resource file" + +[node name="buttons" type="HBoxContainer" parent="container/options"] +layout_mode = 2 +alignment = 2 + +[node name="close" type="Button" parent="container/options/buttons"] +layout_mode = 2 +text = "Close" + +[node name="clear" type="Button" parent="container/options/buttons"] +layout_mode = 2 +text = "Clear" + +[node name="next" type="Button" parent="container/options/buttons"] +layout_mode = 2 +text = "Import" + +[connection signal="button_up" from="container/options/file_location/HBoxContainer/file_location_btn" to="." method="_open_aseprite_file_selection_dialog"] +[connection signal="button_down" from="container/options/layer_section/header/section_header" to="." method="_on_layer_section_header_button_down"] +[connection signal="button_down" from="container/options/animation_section/header/section_header" to="." method="_on_animation_header_button_down"] +[connection signal="button_down" from="container/options/output_section/header/section_header" to="." method="_on_output_section_header_button_down"] +[connection signal="button_up" from="container/options/output_section/section_content/items/output_folder/HBoxContainer/output_folder_btn" to="." method="_open_output_folder_selection_dialog"] +[connection signal="button_up" from="container/options/buttons/close" to="." method="_on_close_btn_up"] +[connection signal="button_up" from="container/options/buttons/clear" to="." method="_on_clear_button_up"] +[connection signal="button_up" from="container/options/buttons/next" to="." method="_on_next_btn_up"] diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/imported_sprite_frames.gd b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/imported_sprite_frames.gd new file mode 100644 index 0000000..30bc9c2 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/imported_sprite_frames.gd @@ -0,0 +1,304 @@ +@tool +extends PanelContainer + +signal import_success(fields) + +const result_code = preload("../../../config/result_codes.gd") +const wizard_config = preload("../../../config/wizard_config.gd") +var _import_helper = preload("./wizard_import_helper.gd").new() + +@onready var _tree_container = $MarginContainer/HSplitContainer/tree +@onready var _resource_tree = _tree_container.get_resource_tree() +@onready var _nothing_container = $MarginContainer/HSplitContainer/MarginContainer/VBoxContainer/nothing +@onready var _single_item_container = $MarginContainer/HSplitContainer/MarginContainer/VBoxContainer/single_item +@onready var _multiple_items_container = $MarginContainer/HSplitContainer/MarginContainer/VBoxContainer/multiple_items +@onready var _confirmation_warning_container = $MarginContainer/HSplitContainer/MarginContainer/VBoxContainer/confirmation_warning + +var _selection_count = 0 + +var _current_container = null +var _resources_to_process = null + +var _is_loaded = false + +var _groups = {} + +func init_resources(): + if _is_loaded: + return + _is_loaded = true + var file_tree = _get_file_tree("res://") + _setup_tree(file_tree) + + +func _get_file_tree(base_path: String, dir_name: String = "") -> Dictionary: + var dir_path = base_path.path_join(dir_name) + var dir = DirAccess.open(dir_path) + var dir_data = { "path": dir_path, "name": dir_name, "children": [], "type": "dir", } + if not dir: + return dir_data + + dir.list_dir_begin() + var file_name = dir.get_next() + + while file_name != "": + if dir.current_is_dir() and _is_importable_folder(dir_path, file_name): + var child_data = _get_file_tree(dir_path, file_name) + if not child_data.children.is_empty(): + dir_data.children.push_back(child_data) + elif file_name.ends_with(".res"): + var resource_path = dir_path.path_join(file_name) + var resource = ResourceLoader.load(resource_path) + if resource is SpriteFrames: + if resource.has_meta(wizard_config.WIZARD_CONFIG_META_NAME): + var meta = resource.get_meta(wizard_config.WIZARD_CONFIG_META_NAME) + var parent_node = dir_data + + if meta.group != "": + var group + if _groups.has(meta.group): + group = _groups[meta.group] + else: + group = { "folders": {} } + _groups[meta.group] = group + + if not group.folders.has(dir_path): + group.folders[dir_path] = { + "node": { + "type": "group", + "name": "Split: %s" % meta.fields.source_file.get_file(), + "has_moved": meta.fields.output_location != dir_path, + "path": meta.fields.source_file, + "folder": dir_path, + "has_changes": _has_source_changes(resource, meta), + "children": [], + } + } + parent_node.children.push_back(group.folders[dir_path].node) + + parent_node = group.folders[dir_path].node + + parent_node.children.push_back({ + "type": "resource", + "resource_type": "SpriteFrames", + "name": resource.resource_path.get_file(), + "path": resource.resource_path, + "meta": meta, + "has_changes": _has_source_changes(resource, meta), + "has_moved": meta.fields.output_location != dir_path, + }) + + file_name = dir.get_next() + + return dir_data + + +func _is_importable_folder(dir_path: String, dir_name: String) -> bool: + return dir_path != "res://" or dir_name != "addons" + + +func _setup_tree(resource_tree: Dictionary) -> void: + var root = _resource_tree.create_item() + _add_items_to_tree(root, resource_tree.children) + + +func _add_items_to_tree(root: TreeItem, children: Array): + for node in children: + var item: TreeItem = _resource_tree.create_item(root) + item.set_text(0, node.name) + item.set_meta("node", node) + match node.type: + "dir": + item.set_icon(0, get_theme_icon("Folder", "EditorIcons")) + _add_items_to_tree(item, node.children) +# + "group": + item.set_icon(0, get_theme_icon("CompressedTexture2D", "EditorIcons")) + _add_items_to_tree(item, node.children) + if node.has_changes: + item.set_text(0, "%s (*)" % node.name) + if node.has_moved: + item.set_suffix(0, "(moved)") + "resource": + item.set_icon(0, get_theme_icon(node.resource_type, "EditorIcons")) + if node.has_changes: + item.set_text(0, "%s (*)" % node.name) + if node.meta.group != "": + item.set_custom_color(0, item.get_icon_modulate(0).darkened(0.5)) + item.set_selectable(0, false) + elif node.has_moved: + item.set_suffix(0, "(moved)") + + +func _has_source_changes(resource: Object, meta: Dictionary) -> bool: + var current_hash = FileAccess.get_md5(meta.fields.source_file) + var saved_hash = wizard_config.get_source_hash(resource) + + return saved_hash != current_hash + + +func _is_supported_type(resource_type: String) -> bool: + return resource_type == "SpriteFrames" + + +func reload_tree(): + _confirmation_warning_container.hide() + _resources_to_process = null + if _current_container != null: + _current_container.show_buttons() + _current_container = null + + _groups = {} + _selection_count = 0 + _resource_tree.clear() + var file_tree = _get_file_tree("res://") + _setup_tree(file_tree) + + +func _set_empty_details_state(): + _nothing_container.show() + _single_item_container.hide() + _multiple_items_container.hide() + + +func _on_tree_multi_selected(item: TreeItem, column: int, selected: bool): + _confirmation_warning_container.hide() + _resources_to_process = null + if _current_container != null: + _current_container.show_buttons() +# + if selected: + _selection_count += 1 + else: + _selection_count -= 1 +# + _nothing_container.hide() + _single_item_container.hide() + _multiple_items_container.hide() +# + match _selection_count: + 0: + _nothing_container.show() + 1: + _single_item_container.show() + _set_item_details(_resource_tree.get_selected()) + _current_container = _single_item_container + _: + _multiple_items_container.show() + _multiple_items_container.set_selected_count(_selection_count) + _current_container = _multiple_items_container + + +func _set_item_details(item: TreeItem) -> void: + if not item.has_meta("node"): + return + var data = item.get_meta("node") + _single_item_container.set_resource_details(data) + + +func _on_single_item_import_triggered(): + var selected = _resource_tree.get_selected() + var meta = selected.get_meta("node") + + match meta.type: + "dir": + var selected_item = _resource_tree.get_selected() + var all_resources = [] + var scenes_to_open = _set_all_resources(selected_item.get_meta("node"), all_resources) + _resources_to_process = all_resources + _show_confirmation_message(all_resources.size()) + "resource": + var code = await _do_import(meta.path, meta.meta) + _set_tree_item_as_saved(_resource_tree.get_selected()) + _single_item_container.hide_source_change_warning() + if code == OK: + EditorInterface.get_resource_filesystem().scan() + "group": + var first_item = meta.children[0] + var code = await _do_import(first_item.path, first_item.meta) + _set_tree_item_as_saved(selected) + _single_item_container.hide_source_change_warning() + if code == OK: + EditorInterface.get_resource_filesystem().scan() + _on_tree_refresh_triggered() + + +func _on_confirmation_warning_warning_confirmed(): + _confirmation_warning_container.hide() + _current_container.show_buttons() + + for resource in _resources_to_process: + await _do_import(resource.path, resource.meta) + + _resources_to_process = null + EditorInterface.get_resource_filesystem().scan() + _on_tree_refresh_triggered() + + +func _on_confirmation_warning_warning_declined(): + _confirmation_warning_container.hide() + _current_container.show_buttons() + _resources_to_process = null + + +func _on_tree_refresh_triggered(): + _set_empty_details_state() + reload_tree() + + +func _set_tree_item_as_saved(item: TreeItem) -> void: + var meta = item.get_meta("node") + meta.has_changes = false + meta.has_moved = false + item.set_meta("node", meta) + item.set_text(0, meta.name) + item.set_suffix(0, "") + + +func _do_import(resource_path: String, metadata: Dictionary) -> int: + var resource_base_dir = resource_path.get_base_dir() + + if resource_base_dir != metadata.fields.output_location: + print("Resource has moved. Changing output folder from %s to %s" % [resource_base_dir, metadata.fields.output_location]) + metadata.fields.output_location = resource_base_dir + + var exit_code := await _import_helper.import_and_create_resources(metadata.fields.source_file, metadata.fields) + + if exit_code == OK: + print("Import complete: %s" % resource_path) + import_success.emit(metadata.fields) + else: + printerr("Failed to import %s. Error: %s" % [resource_path, result_code.get_error_message(exit_code)]) + + return exit_code + + +func _set_all_resources(meta: Dictionary, resources: Array): + match meta.type: + "dir": + for c in meta.children: + _set_all_resources(c, resources) + "resource": + if not resources.has(meta): + resources.push_back(meta) + "group": + var first_item = meta.children[0] + resources.push_back(first_item) + + +func _show_confirmation_message(resources: int): + _current_container.hide_buttons() + _confirmation_warning_container.set_message("You are about to re-import %s resources. Do you wish to continue?" % resources) + _confirmation_warning_container.show() + + +func _on_multiple_items_import_triggered(): + var selected_item = _resource_tree.get_next_selected(null) + var all_resources = [] + + while selected_item != null: + _set_all_resources(selected_item.get_meta("node"), all_resources) + selected_item = _resource_tree.get_next_selected(selected_item) + + _resources_to_process = all_resources + _show_confirmation_message(all_resources.size()) diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/imported_sprite_frames.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/imported_sprite_frames.gd.uid new file mode 100644 index 0000000..2003e61 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/imported_sprite_frames.gd.uid @@ -0,0 +1 @@ +uid://dks0ne1sw10ni diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/imported_sprite_frames.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/imported_sprite_frames.tscn new file mode 100644 index 0000000..ca76e18 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/imported_sprite_frames.tscn @@ -0,0 +1,67 @@ +[gd_scene load_steps=6 format=3 uid="uid://bfhsdslj8kt7b"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/docks/wizard/imported_sprite_frames.gd" id="1_dk2ra"] +[ext_resource type="PackedScene" uid="uid://cisgsfvp4nf1g" path="res://addons/AsepriteWizard/interface/shared/tree/resource_tree.tscn" id="2_svrqo"] +[ext_resource type="PackedScene" uid="uid://q7eyyg2kvvv2" path="res://addons/AsepriteWizard/interface/docks/wizard/resource_tree_single_item.tscn" id="3_pe1cg"] +[ext_resource type="PackedScene" uid="uid://fscemkx5w1dw" path="res://addons/AsepriteWizard/interface/docks/wizard/resource_tree_multiple_items.tscn" id="4_vteew"] +[ext_resource type="PackedScene" uid="uid://qgmln507kjnm" path="res://addons/AsepriteWizard/interface/shared/tree/tree_selection_confirmation_warning.tscn" id="5_jigim"] + +[node name="ImportedSpriteFrames" type="PanelContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_dk2ra") + +[node name="MarginContainer" type="MarginContainer" parent="."] +layout_mode = 2 + +[node name="HSplitContainer" type="HSplitContainer" parent="MarginContainer"] +layout_mode = 2 + +[node name="tree" parent="MarginContainer/HSplitContainer" instance=ExtResource("2_svrqo")] +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/HSplitContainer"] +custom_minimum_size = Vector2(200, 0) +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/HSplitContainer/MarginContainer"] +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/HSplitContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="MarginContainer/HSplitContainer/MarginContainer/VBoxContainer/MarginContainer"] +layout_mode = 2 +text = "Details" +horizontal_alignment = 1 + +[node name="HSeparator" type="HSeparator" parent="MarginContainer/HSplitContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="nothing" type="Label" parent="MarginContainer/HSplitContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 6 +text = "Nothing selected" +horizontal_alignment = 1 + +[node name="single_item" parent="MarginContainer/HSplitContainer/MarginContainer/VBoxContainer" instance=ExtResource("3_pe1cg")] +visible = false +layout_mode = 2 + +[node name="multiple_items" parent="MarginContainer/HSplitContainer/MarginContainer/VBoxContainer" instance=ExtResource("4_vteew")] +visible = false +layout_mode = 2 + +[node name="confirmation_warning" parent="MarginContainer/HSplitContainer/MarginContainer/VBoxContainer" instance=ExtResource("5_jigim")] +visible = false +layout_mode = 2 + +[connection signal="multi_selected" from="MarginContainer/HSplitContainer/tree" to="." method="_on_tree_multi_selected"] +[connection signal="refresh_triggered" from="MarginContainer/HSplitContainer/tree" to="." method="_on_tree_refresh_triggered"] +[connection signal="import_triggered" from="MarginContainer/HSplitContainer/MarginContainer/VBoxContainer/single_item" to="." method="_on_single_item_import_triggered"] +[connection signal="import_triggered" from="MarginContainer/HSplitContainer/MarginContainer/VBoxContainer/multiple_items" to="." method="_on_multiple_items_import_triggered"] +[connection signal="warning_confirmed" from="MarginContainer/HSplitContainer/MarginContainer/VBoxContainer/confirmation_warning" to="." method="_on_confirmation_warning_warning_confirmed"] +[connection signal="warning_declined" from="MarginContainer/HSplitContainer/MarginContainer/VBoxContainer/confirmation_warning" to="." method="_on_confirmation_warning_warning_declined"] diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_multiple_items.gd b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_multiple_items.gd new file mode 100644 index 0000000..cf8882b --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_multiple_items.gd @@ -0,0 +1,22 @@ +@tool +extends VBoxContainer + +signal import_triggered + +@onready var _import_message = $message +@onready var _import_button = $buttons + +func set_selected_count(number_of_items: int) -> void: + _import_message.text = "%2d items selected" % number_of_items + + +func show_buttons(): + _import_button.show() + + +func hide_buttons(): + _import_button.hide() + + +func _on_import_selected_button_up(): + import_triggered.emit() diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_multiple_items.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_multiple_items.gd.uid new file mode 100644 index 0000000..1b5b655 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_multiple_items.gd.uid @@ -0,0 +1 @@ +uid://3bikkl8oy8q4 diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_multiple_items.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_multiple_items.tscn new file mode 100644 index 0000000..7e14c48 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_multiple_items.tscn @@ -0,0 +1,24 @@ +[gd_scene load_steps=2 format=3 uid="uid://fscemkx5w1dw"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/docks/wizard/resource_tree_multiple_items.gd" id="1_lg81l"] + +[node name="multiple_items" type="VBoxContainer"] +size_flags_vertical = 3 +script = ExtResource("1_lg81l") + +[node name="message" type="Label" parent="."] +layout_mode = 2 +size_flags_vertical = 6 +text = "Multiple items selected +" +horizontal_alignment = 1 + +[node name="buttons" type="HFlowContainer" parent="."] +layout_mode = 2 + +[node name="import_selected" type="Button" parent="buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Re-Import all" + +[connection signal="button_up" from="buttons/import_selected" to="." method="_on_import_selected_button_up"] diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_single_item.gd b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_single_item.gd new file mode 100644 index 0000000..76c5b86 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_single_item.gd @@ -0,0 +1,171 @@ +@tool +extends VBoxContainer + +signal import_triggered + +@onready var _file_name = $GridContainer/file_name_value +@onready var _type = $GridContainer/type_value +@onready var _path = $GridContainer/path_value + +@onready var _source_label = $GridContainer/source_file_label +@onready var _source = $GridContainer/source_file_value +@onready var _only_visible_layers_label = $GridContainer/only_visible_layers_label +@onready var _only_visible_layers = $GridContainer/only_visible_layers_value +@onready var _layer_ex_pattern_label = $GridContainer/layer_ex_patt_label +@onready var _layer_ex_pattern = $GridContainer/layer_ex_patt_value + +@onready var _o_name_label = $GridContainer/o_name_label +@onready var _o_name = $GridContainer/o_name_value +@onready var _o_folder_label = $GridContainer/o_folder_label +@onready var _o_folder_value = $GridContainer/o_folder_value + +@onready var _resource_list_label = $GridContainer/resource_list_label +@onready var _resource_list = $GridContainer/resource_list +@onready var _resource_list_separator_1 = $GridContainer/HSeparator3 +@onready var _resource_list_separator_2 = $GridContainer/HSeparator4 + +@onready var _resource_buttons = $resource_buttons +@onready var _dir_buttons = $dir_buttons +@onready var _group_buttons = $group_buttons + +@onready var _source_change_warning = $source_changed_warning + +@onready var _resource_only_fields = [ + _source_label, + _source, + _only_visible_layers_label, + _only_visible_layers, + _layer_ex_pattern_label, + _layer_ex_pattern, + _o_name_label, + _o_name, + _o_folder_label, + _o_folder_value, + _source_change_warning, +] + +var _current_resource_type = "resource" +var _resource_config: Dictionary = {} + +func _ready(): + _source_change_warning.set_text("Source file changed since last import") + _source_change_warning.hide() + + +func set_resource_details(resource_details: Dictionary) -> void: + _resource_config = resource_details + _resource_buttons.hide() + _dir_buttons.hide() + _group_buttons.hide() + _hide_resource_list() + + _source_change_warning.hide() + + _file_name.text = resource_details.name + _path.text = resource_details.path + + _current_resource_type = resource_details.type + match resource_details.type: + "resource": + _type.text = resource_details.resource_type + _show_resource_fields() + _resource_buttons.show() + + var fields = resource_details.meta.fields + _load_fields(fields) + _resource_buttons.show() + _source_change_warning.visible = resource_details.has_changes + "group": + _type.text = "Split Group" + _show_resource_fields() + _load_fields(resource_details.children[0].meta.fields) + _source_change_warning.visible = resource_details.children[0].has_changes + _group_buttons.show() + _show_resource_list() + for c in _resource_list.get_children(): + c.queue_free() + + for child_resource in resource_details.children: + var label = Label.new() + label.text = child_resource.name + _resource_list.add_child(label) + _: + _type.text = "Folder" + _hide_resource_fields() + _dir_buttons.show() + return + + +func _load_fields(fields: Dictionary): + _only_visible_layers.text = "Yes" if fields.only_visible_layers else "No" + _layer_ex_pattern.text = fields.layer_exclusion_pattern + + _o_name.text = fields.output_name + _o_folder_value.text = fields.output_location + + _source.text = fields.source_file + + +func _hide_resource_fields(): + for f in _resource_only_fields: + f.hide() + + +func _show_resource_fields(): + for f in _resource_only_fields: + f.show() + + +func show_buttons(): + match _current_resource_type: + "resource": + _resource_buttons.show() + _: + _dir_buttons.show() + + +func hide_buttons(): + _resource_buttons.hide() + _dir_buttons.hide() + + +func hide_source_change_warning(): + _source_change_warning.hide() + + +func _on_show_in_fs_button_up(): + EditorInterface.get_file_system_dock().navigate_to_path(_path.text) + + +func _on_show_dir_in_fs_button_up(): + EditorInterface.get_file_system_dock().navigate_to_path(_path.text) + + +func _on_import_all_button_up(): + import_triggered.emit() + + +func _on_import_button_up(): + import_triggered.emit() + + +func _hide_resource_list(): + _resource_list_separator_1.hide() + _resource_list_separator_2.hide() + _resource_list_label.hide() + _resource_list.hide() + + +func _show_resource_list(): + _resource_list_separator_1.show() + _resource_list_separator_2.show() + _resource_list_label.show() + _resource_list.show() + + +func _on_import_all_pressed(): + import_triggered.emit() + + +func _on_show_in_fs_pressed(): + EditorInterface.get_file_system_dock().navigate_to_path(_resource_config.children[0].path) diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_single_item.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_single_item.gd.uid new file mode 100644 index 0000000..27ebd5c --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_single_item.gd.uid @@ -0,0 +1 @@ +uid://bqm21qpd6pl3f diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_single_item.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_single_item.tscn new file mode 100644 index 0000000..9603625 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/resource_tree_single_item.tscn @@ -0,0 +1,172 @@ +[gd_scene load_steps=3 format=3 uid="uid://q7eyyg2kvvv2"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/docks/wizard/resource_tree_single_item.gd" id="1_h1q4t"] +[ext_resource type="PackedScene" uid="uid://c1l0bk12iwln3" path="res://addons/AsepriteWizard/interface/shared/tree/inline_warning_panel.tscn" id="2_hmv61"] + +[node name="single_item" type="VBoxContainer"] +script = ExtResource("1_h1q4t") + +[node name="GridContainer" type="GridContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +theme_override_constants/h_separation = 10 +columns = 2 + +[node name="type_label" type="Label" parent="GridContainer"] +layout_mode = 2 +size_flags_vertical = 0 +text = "Type" + +[node name="type_value" type="Label" parent="GridContainer"] +layout_mode = 2 +text = "-" + +[node name="file_name_label" type="Label" parent="GridContainer"] +layout_mode = 2 +size_flags_vertical = 0 +text = "File" + +[node name="file_name_value" type="Label" parent="GridContainer"] +custom_minimum_size = Vector2(50, 0) +layout_mode = 2 +text = "-" +autowrap_mode = 1 + +[node name="path_label" type="Label" parent="GridContainer"] +layout_mode = 2 +size_flags_vertical = 0 +text = "Path" + +[node name="path_value" type="Label" parent="GridContainer"] +custom_minimum_size = Vector2(50, 0) +layout_mode = 2 +size_flags_horizontal = 3 +text = "-" +autowrap_mode = 1 + +[node name="HSeparator" type="HSeparator" parent="GridContainer"] +layout_mode = 2 + +[node name="HSeparator2" type="HSeparator" parent="GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="source_file_label" type="Label" parent="GridContainer"] +layout_mode = 2 +size_flags_vertical = 0 +text = "Aseprite File" + +[node name="source_file_value" type="Label" parent="GridContainer"] +custom_minimum_size = Vector2(50, 0) +layout_mode = 2 +size_flags_horizontal = 3 +text = "-" +autowrap_mode = 1 + +[node name="only_visible_layers_label" type="Label" parent="GridContainer"] +layout_mode = 2 +size_flags_vertical = 0 +text = "Only Visible Layers" + +[node name="only_visible_layers_value" type="Label" parent="GridContainer"] +layout_mode = 2 +text = "-" + +[node name="layer_ex_patt_label" type="Label" parent="GridContainer"] +layout_mode = 2 +size_flags_vertical = 0 +text = "Slice" + +[node name="layer_ex_patt_value" type="Label" parent="GridContainer"] +layout_mode = 2 +text = "-" + +[node name="o_folder_label" type="Label" parent="GridContainer"] +visible = false +layout_mode = 2 +size_flags_vertical = 0 +text = "Output Folder" + +[node name="o_folder_value" type="Label" parent="GridContainer"] +visible = false +custom_minimum_size = Vector2(50, 0) +layout_mode = 2 +size_flags_horizontal = 3 +text = "-" +autowrap_mode = 2 + +[node name="o_name_label" type="Label" parent="GridContainer"] +layout_mode = 2 +size_flags_vertical = 0 +text = "Output Name" + +[node name="o_name_value" type="Label" parent="GridContainer"] +layout_mode = 2 +text = "-" + +[node name="HSeparator3" type="HSeparator" parent="GridContainer"] +layout_mode = 2 + +[node name="HSeparator4" type="HSeparator" parent="GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="resource_list_label" type="Label" parent="GridContainer"] +layout_mode = 2 +size_flags_vertical = 0 +text = "Resources" + +[node name="resource_list" type="VBoxContainer" parent="GridContainer"] +layout_mode = 2 + +[node name="source_changed_warning" parent="." instance=ExtResource("2_hmv61")] +layout_mode = 2 + +[node name="resource_buttons" type="HFlowContainer" parent="."] +visible = false +layout_mode = 2 + +[node name="import" type="Button" parent="resource_buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Re-Import" + +[node name="show_in_fs" type="Button" parent="resource_buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Show In FileSystem" + +[node name="group_buttons" type="HFlowContainer" parent="."] +visible = false +layout_mode = 2 + +[node name="import_all" type="Button" parent="group_buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Re-Import all" + +[node name="show_in_fs" type="Button" parent="group_buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Show In FileSystem" + +[node name="dir_buttons" type="HFlowContainer" parent="."] +visible = false +layout_mode = 2 + +[node name="import_all" type="Button" parent="dir_buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Re-Import all" + +[node name="show_dir_in_fs" type="Button" parent="dir_buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Show In FileSystem" + +[connection signal="button_up" from="resource_buttons/import" to="." method="_on_import_button_up"] +[connection signal="button_up" from="resource_buttons/show_in_fs" to="." method="_on_show_in_fs_button_up"] +[connection signal="pressed" from="group_buttons/import_all" to="." method="_on_import_all_pressed"] +[connection signal="pressed" from="group_buttons/show_in_fs" to="." method="_on_show_in_fs_pressed"] +[connection signal="button_up" from="dir_buttons/import_all" to="." method="_on_import_all_button_up"] +[connection signal="button_up" from="dir_buttons/show_dir_in_fs" to="." method="_on_show_dir_in_fs_button_up"] diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/sprite_frames_import_history.gd b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/sprite_frames_import_history.gd new file mode 100644 index 0000000..1ed5845 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/sprite_frames_import_history.gd @@ -0,0 +1,236 @@ +@tool +extends PanelContainer + +signal request_edit(import_cfg) +signal request_import(import_cfg) + +const SourcePathField = preload("./wizard_nodes/source_path.tscn") +const OutputPathField = preload("./wizard_nodes/output_path.tscn") +const ImportDateField = preload("./wizard_nodes/import_date.tscn") +const ItemActions = preload("./wizard_nodes/list_actions.tscn") +const DetailsField = preload("./wizard_nodes/details.tscn") + +const SORT_BY_DATE := 0 +const SORT_BY_PATH := 1 +const INITIAL_GRID_INDEX := 4 + +var _config = preload("../../../config/config.gd").new() +var _history: Array +var _history_nodes := {} +var _history_nodes_list := [] +var _is_busy := false +var _import_requested_for := -1 +var _sort_by = SORT_BY_DATE + +@onready var grid = $MarginContainer/VBoxContainer/ScrollContainer/GridContainer +@onready var loading_warning = $MarginContainer/VBoxContainer/loading_warning +@onready var no_history_warning = $MarginContainer/VBoxContainer/no_history_warning + + +func reload(): + if _history: + return + + _history = _config.get_import_history() + + for index in range(_history.size()): + var entry = _history[index] + _create_node_list_entry(entry, index) + + loading_warning.hide() + if _history.is_empty(): + no_history_warning.show() + else: + grid.get_parent().show() + + +func _create_node_list_entry(entry: Dictionary, index: int): + _add_to_node_list(entry, _create_nodes(entry, index)) + + +func _create_nodes(entry: Dictionary, index: int) -> Dictionary: + var import_date = ImportDateField.instantiate() + import_date.set_date(entry.import_date) + + var source_path = SourcePathField.instantiate() + source_path.set_entry(entry) + + var output_path = OutputPathField.instantiate() + output_path.text = entry.output_location + output_path.tooltip_text = entry.output_location + + var details = DetailsField.instantiate() + details.set_details(entry) + + var actions = ItemActions.instantiate() + actions.history_index = index + actions.connect("import_clicked",Callable(self,"_on_entry_reimport_clicked")) + actions.connect("edit_clicked",Callable(self,"_on_entry_edit_clicked")) + actions.connect("removed_clicked",Callable(self,"_on_entry_remove_clicked")) + + + grid.get_child(INITIAL_GRID_INDEX).add_sibling(import_date) + import_date.add_sibling(source_path) + source_path.add_sibling(output_path) + output_path.add_sibling(details) + details.add_sibling(actions) + + return { + "history_index": index, + "timestamp": entry.import_date, + "source_file": entry.source_file, + "source_path_node": source_path, + "output_path_node": output_path, + "import_date_node": import_date, + "actions_node": actions, + "details_node": details, + } + + +func _add_to_node_list(entry: Dictionary, node: Dictionary): + if not _history_nodes.has(entry.source_file): + _history_nodes[entry.source_file] = [] + _history_nodes[entry.source_file].push_front(node) + _history_nodes_list.push_front(node) + + +func add_entry(file_settings: Dictionary): + if _history == null: + reload() +# + var dt = Time.get_datetime_dict_from_system() + file_settings["import_date"] = "%04d-%02d-%02d %02d:%02d:%02d" % [dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second] +# + if _import_requested_for != -1: + _remove_item(_import_requested_for) + _import_requested_for = -1 + elif _history.size() > _config.get_history_max_entries(): + _remove_entries(_history[0].source_file, 0) +# + _history.push_back(file_settings) + _config.save_import_history(_history) + _create_node_list_entry(file_settings, _history.size() - 1) + + if _sort_by == SORT_BY_PATH: + _trigger_sort() + + no_history_warning.hide() + loading_warning.hide() + grid.get_parent().show() + _is_busy = false + + +func _on_entry_reimport_clicked(entry_index: int): + if _is_busy: + return + _is_busy = true + _import_requested_for = entry_index + emit_signal("request_import", _history[entry_index]) + + +func _on_entry_edit_clicked(entry_index: int): + if _is_busy: + return + emit_signal("request_edit", _history[entry_index]) + + +func _on_entry_remove_clicked(entry_index: int): + if _is_busy: + return + _is_busy = true + + _remove_item(entry_index) + _config.save_import_history(_history) + + if (_history.is_empty()): + grid.get_parent().hide() + no_history_warning.show() + + _is_busy = false + + +func _remove_item(entry_index: int): + var entry = _history[entry_index] + _remove_entries(entry.source_file, entry_index) + + +# removes nodes and entry from history. If entry_index is not provided, all +# entries for path are removed. +func _remove_entries(source_file_path: String, entry_index: int = -1): + var files_entries = _history_nodes[source_file_path] + var indexes_to_remove = [] + + for f in files_entries: + if entry_index == -1 or f.history_index == entry_index: + _free_entry_nodes(f) + _history_nodes_list.erase(f) + + if entry_index != -1: + files_entries.erase(f) + _remove_from_history(f.history_index) + return + + indexes_to_remove.push_back(f.history_index) + + for i in indexes_to_remove: + _remove_from_history(i) + + _history_nodes[source_file_path] = [] + + +func _remove_from_history(entry_index: int): + var _already_adjusted = [] + # to avoid re-creating the whole nodes list, I just decrement + # the index from items newer than the excluded one + for index in range(entry_index + 1, _history.size()): + if _already_adjusted.has(_history[index].source_file): + continue + _already_adjusted.push_back(_history[index].source_file) + var nodes = _history_nodes[_history[index].source_file] + for f in nodes: + if f.history_index > entry_index: + f.history_index -= 1 + f.actions_node.history_index = f.history_index + + _history.remove_at(entry_index) + + +func _free_entry_nodes(entry_history_node: Dictionary): + entry_history_node.source_path_node.queue_free() + entry_history_node.output_path_node.queue_free() + entry_history_node.import_date_node.queue_free() + entry_history_node.actions_node.queue_free() + entry_history_node.details_node.queue_free() + + +func _on_SortOptions_item_selected(index): + if index == _sort_by: + return + + _trigger_sort(index) + + +func _trigger_sort(sort_type: int = _sort_by): + if sort_type == SORT_BY_DATE: + _history_nodes_list.sort_custom(Callable(self,"_sort_by_date")) + else: + _history_nodes_list.sort_custom(Callable(self,"_sort_by_path")) + _reorganise_nodes() + _sort_by = sort_type + + +func _sort_by_date(a, b): + return a.timestamp < b.timestamp + + +func _sort_by_path(a, b): + return a.source_file > b.source_file + + +func _reorganise_nodes(): + for entry in _history_nodes_list: + grid.move_child(entry.import_date_node, INITIAL_GRID_INDEX + 1) + grid.move_child(entry.source_path_node, INITIAL_GRID_INDEX + 2) + grid.move_child(entry.output_path_node, INITIAL_GRID_INDEX + 3) + grid.move_child(entry.details_node, INITIAL_GRID_INDEX + 4) + grid.move_child(entry.actions_node, INITIAL_GRID_INDEX + 5) diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/sprite_frames_import_history.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/sprite_frames_import_history.gd.uid new file mode 100644 index 0000000..b3cce75 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/sprite_frames_import_history.gd.uid @@ -0,0 +1 @@ +uid://cm8y8ip85no0w diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/sprite_frames_import_history.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/sprite_frames_import_history.tscn new file mode 100644 index 0000000..f4f93e5 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/sprite_frames_import_history.tscn @@ -0,0 +1,85 @@ +[gd_scene load_steps=2 format=3 uid="uid://cyoin5ncul0fm"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/docks/wizard/sprite_frames_import_history.gd" id="1"] + +[node name="SpriteFramesImportHistory" type="PanelContainer"] +anchors_preset = 10 +anchor_right = 1.0 +grow_horizontal = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource("1") + +[node name="MarginContainer" type="MarginContainer" parent="."] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] +layout_mode = 2 + +[node name="list actions" type="HBoxContainer" parent="MarginContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 0 +alignment = 2 + +[node name="divider" type="Label" parent="MarginContainer/VBoxContainer/list actions"] +layout_mode = 2 + +[node name="sort_label" type="Label" parent="MarginContainer/VBoxContainer/list actions"] +layout_mode = 2 +text = "Sort by:" + +[node name="SortOptions" type="OptionButton" parent="MarginContainer/VBoxContainer/list actions"] +layout_mode = 2 +item_count = 2 +selected = 0 +popup/item_0/text = "Date" +popup/item_0/id = 0 +popup/item_1/text = "Source File" +popup/item_1/id = 1 + +[node name="loading_warning" type="Label" parent="MarginContainer/VBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 6 +text = "Loading..." + +[node name="no_history_warning" type="Label" parent="MarginContainer/VBoxContainer"] +visible = false +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 6 +text = "No import history" + +[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer"] +visible = false +layout_mode = 2 +size_flags_vertical = 3 + +[node name="GridContainer" type="GridContainer" parent="MarginContainer/VBoxContainer/ScrollContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +columns = 5 + +[node name="date_label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/GridContainer"] +layout_mode = 2 +text = "Date" + +[node name="source_label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "Source File" + +[node name="output_label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/GridContainer"] +layout_mode = 2 +text = "Output Folder" + +[node name="details_label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/GridContainer"] +layout_mode = 2 +text = "Details" + +[node name="actions_label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/GridContainer"] +layout_mode = 2 +text = "Actions" + +[connection signal="item_selected" from="MarginContainer/VBoxContainer/list actions/SortOptions" to="." method="_on_SortOptions_item_selected"] diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_import_helper.gd b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_import_helper.gd new file mode 100644 index 0000000..7e2b67e --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_import_helper.gd @@ -0,0 +1,70 @@ +@tool +extends Node + +const wizard_meta = preload("../../../config/wizard_config.gd") +const result_code = preload("../../../config/result_codes.gd") +var _aseprite_file_exporter = preload("../../../aseprite/file_exporter.gd").new() +var _sf_creator = preload("../../../creators/sprite_frames/sprite_frames_creator.gd").new() +var _config = preload("../../../config/config.gd").new() + +var _file_system: EditorFileSystem = EditorInterface.get_resource_filesystem() + + +# fields +# "split_layers" +# "only_visible_layers" +# "layer_exclusion_pattern" +# "output_name" +# "source_file" +# "do_not_create_resource" +# "output_location" +# "should_round_fps" +func import_and_create_resources(aseprite_file: String, fields: Dictionary) -> int: + var export_mode = _aseprite_file_exporter.LAYERS_EXPORT_MODE if fields.split_layers else _aseprite_file_exporter.FILE_EXPORT_MODE + var options = { + "export_mode": export_mode, + "exception_pattern": fields.layer_exclusion_pattern, + "only_visible_layers": fields.only_visible_layers, + "output_filename": fields.output_name, + "do_not_create_resource": fields.do_not_create_resource, + "output_folder": fields.output_location, + } + + var aseprite_output = _aseprite_file_exporter.generate_aseprite_files( + ProjectSettings.globalize_path(aseprite_file), + options + ) + + if not aseprite_output.is_ok: + return aseprite_output.code + + _file_system.scan() + + await _file_system.filesystem_changed + + var exit_code = OK + + if !options.get("do_not_create_resource", false): + var resources = _sf_creator.create_resources(aseprite_output.content, { "should_round_fps": fields.get("should_round_fps", true) }) + if resources.is_ok: + _add_metadata(resources.content, aseprite_file, fields, options) + exit_code = _sf_creator.save_resources(resources.content) + + if _config.should_remove_source_files(): + _remove_source_files(aseprite_output.content) + + return exit_code + + +func _add_metadata(resources: Array, aseprite_file: String, fields: Dictionary, options: Dictionary) -> void: + var source_hash = FileAccess.get_md5(aseprite_file) + var group = str(ResourceUID.create_id()) if options.export_mode == _aseprite_file_exporter.LAYERS_EXPORT_MODE else "" + + for r in resources: + wizard_meta.set_source_hash(r.resource, source_hash) + wizard_meta.save_config(r.resource, { "fields": fields, "group": group }) + + +func _remove_source_files(source_files: Array): + for s in source_files: + DirAccess.remove_absolute(s.data_file) diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_import_helper.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_import_helper.gd.uid new file mode 100644 index 0000000..40c4d65 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_import_helper.gd.uid @@ -0,0 +1 @@ +uid://c7x0ejkherx43 diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/details.gd b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/details.gd new file mode 100644 index 0000000..bed082f --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/details.gd @@ -0,0 +1,42 @@ +@tool +extends VBoxContainer + +@onready var _details_btn = $label +@onready var _details_container = $MarginContainer/GridContainer + +@onready var _split_layers_field = $MarginContainer/GridContainer/split_layers +@onready var _only_visible_layers = $MarginContainer/GridContainer/only_visible_layers +@onready var _layer_exclusion_pattern = $MarginContainer/GridContainer/layer_exclusion_pattern +@onready var _output_name = $MarginContainer/GridContainer/output_name +@onready var _do_not_create_resource = $MarginContainer/GridContainer/do_not_create_resource + +var _entry + +func _ready(): + _adjust_icon(false) + _details_container.hide() + _load_fields() + + +func set_details(entry: Dictionary): + _entry = entry + + +func _load_fields(): + _split_layers_field.text = "Yes" if _entry.split_layers else "No" + _only_visible_layers.text = "Yes" if _entry.only_visible_layers else "No" + _layer_exclusion_pattern.text = _entry.layer_exclusion_pattern + _output_name.text = _entry.output_name + _output_name.text = _entry.output_name + _do_not_create_resource.text = "Yes" if _entry.do_not_create_resource else "No" + + +func _adjust_icon(is_visible: bool) -> void: + var icon_name = "GuiTreeArrowDown" if is_visible else "GuiTreeArrowRight" + _details_btn.icon = get_theme_icon(icon_name, "EditorIcons") + + +func _on_label_pressed(): + _details_container.visible = not _details_container.visible + _adjust_icon(_details_container.visible) + diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/details.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/details.gd.uid new file mode 100644 index 0000000..56752a7 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/details.gd.uid @@ -0,0 +1 @@ +uid://xhqjfqh7svgs diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/details.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/details.tscn new file mode 100644 index 0000000..b6034ce --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/details.tscn @@ -0,0 +1,60 @@ +[gd_scene load_steps=2 format=3 uid="uid://b1jb5yierm2bq"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/details.gd" id="1_1v4dc"] + +[node name="Details" type="VBoxContainer"] +offset_right = 40.0 +offset_bottom = 40.0 +script = ExtResource("1_1v4dc") + +[node name="label" type="Button" parent="."] +layout_mode = 2 +text = "Details" +flat = true +alignment = 0 + +[node name="MarginContainer" type="MarginContainer" parent="."] +layout_mode = 2 +theme_override_constants/margin_left = 10 + +[node name="GridContainer" type="GridContainer" parent="MarginContainer"] +layout_mode = 2 +theme_override_constants/h_separation = 5 +columns = 2 + +[node name="split_layers_label" type="Label" parent="MarginContainer/GridContainer"] +layout_mode = 2 +text = "Split layers:" + +[node name="split_layers" type="Label" parent="MarginContainer/GridContainer"] +layout_mode = 2 + +[node name="only_visible_layers_label" type="Label" parent="MarginContainer/GridContainer"] +layout_mode = 2 +text = "Only visible layers:" + +[node name="only_visible_layers" type="Label" parent="MarginContainer/GridContainer"] +layout_mode = 2 + +[node name="layer_exclusion_pattern_label" type="Label" parent="MarginContainer/GridContainer"] +layout_mode = 2 +text = "Layer Ex Pattern:" + +[node name="layer_exclusion_pattern" type="Label" parent="MarginContainer/GridContainer"] +layout_mode = 2 + +[node name="output_name_label" type="Label" parent="MarginContainer/GridContainer"] +layout_mode = 2 +text = "Output name:" + +[node name="output_name" type="Label" parent="MarginContainer/GridContainer"] +layout_mode = 2 + +[node name="do_not_create_resource_label" type="Label" parent="MarginContainer/GridContainer"] +layout_mode = 2 +text = "Do not create resource:" + +[node name="do_not_create_resource" type="Label" parent="MarginContainer/GridContainer"] +layout_mode = 2 + +[connection signal="pressed" from="label" to="." method="_on_label_pressed"] diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/import_date.gd b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/import_date.gd new file mode 100644 index 0000000..0942752 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/import_date.gd @@ -0,0 +1,6 @@ +@tool +extends Label + + +func set_date(timestamp: String): + self.text = timestamp diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/import_date.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/import_date.gd.uid new file mode 100644 index 0000000..08dc778 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/import_date.gd.uid @@ -0,0 +1 @@ +uid://dktui4m0vumbc diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/import_date.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/import_date.tscn new file mode 100644 index 0000000..aec0cb3 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/import_date.tscn @@ -0,0 +1,12 @@ +[gd_scene load_steps=2 format=3 uid="uid://bs0i357m5d7ho"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/import_date.gd" id="1"] + +[node name="import_date" type="Label"] +offset_left = 660.0 +offset_top = 39.0 +offset_right = 774.0 +offset_bottom = 53.0 +size_flags_vertical = 0 +text = "2022-07-18 18:01" +script = ExtResource("1") diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/list_actions.gd b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/list_actions.gd new file mode 100644 index 0000000..ace8376 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/list_actions.gd @@ -0,0 +1,20 @@ +@tool +extends HBoxContainer + +signal import_clicked(index) +signal edit_clicked(index) +signal removed_clicked(index) + +var history_index = -1 + + +func _on_edit_pressed(): + emit_signal("edit_clicked", history_index) + + +func _on_reimport_pressed(): + emit_signal("import_clicked", history_index) + + +func _on_remove_pressed(): + emit_signal("removed_clicked", history_index) diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/list_actions.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/list_actions.gd.uid new file mode 100644 index 0000000..27d7bc3 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/list_actions.gd.uid @@ -0,0 +1 @@ +uid://de4ch4nrcq77d diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/list_actions.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/list_actions.tscn new file mode 100644 index 0000000..b620fad --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/list_actions.tscn @@ -0,0 +1,35 @@ +[gd_scene load_steps=2 format=3] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/list_actions.gd" id="1"] + +[node name="actions" type="HBoxContainer"] +offset_left = 784.0 +offset_top = 34.0 +offset_right = 950.0 +offset_bottom = 58.0 +custom_constants/separation = 5 +script = ExtResource( 1 ) + +[node name="edit" type="Button" parent="."] +offset_right = 36.0 +offset_bottom = 20.0 +size_flags_vertical = 0 +text = "Edit" + +[node name="reimport" type="Button" parent="."] +offset_left = 41.0 +offset_right = 97.0 +offset_bottom = 20.0 +size_flags_vertical = 0 +text = "Import" + +[node name="remove_at" type="Button" parent="."] +offset_left = 102.0 +offset_right = 166.0 +offset_bottom = 20.0 +size_flags_vertical = 0 +text = "Remove" + +[connection signal="pressed" from="edit" to="." method="_on_edit_pressed"] +[connection signal="pressed" from="reimport" to="." method="_on_reimport_pressed"] +[connection signal="pressed" from="remove_at" to="." method="_on_remove_pressed"] diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/output_path.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/output_path.tscn new file mode 100644 index 0000000..6b9fa5b --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/output_path.tscn @@ -0,0 +1,12 @@ +[gd_scene format=2] + +[node name="output_path" type="LineEdit"] +offset_left = 450.0 +offset_top = 34.0 +offset_right = 650.0 +offset_bottom = 58.0 +minimum_size = Vector2( 200, 0 ) +size_flags_vertical = 0 +text = "/some/output" +align = 3 +editable = false diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/source_path.gd b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/source_path.gd new file mode 100644 index 0000000..c49de38 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/source_path.gd @@ -0,0 +1,6 @@ +@tool +extends LineEdit + +func set_entry(entry: Dictionary): + self.text = entry.source_file + self.tooltip_text = entry.source_file diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/source_path.gd.uid b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/source_path.gd.uid new file mode 100644 index 0000000..17c6607 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/source_path.gd.uid @@ -0,0 +1 @@ +uid://b2k4l876fqgjn diff --git a/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/source_path.tscn b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/source_path.tscn new file mode 100644 index 0000000..c28e803 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/source_path.tscn @@ -0,0 +1,18 @@ +[gd_scene load_steps=2 format=3] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/docks/wizard/wizard_nodes/source_path.gd" id="1"] + +[node name="source_path" type="LineEdit"] +offset_top = 34.0 +offset_right = 440.0 +offset_bottom = 58.0 +minimum_size = Vector2( 200, 0 ) +tooltip_text = "Output name / prefix: some_name +Ex. Pattern: $_ +Split: Yes +Only Visible: No +No Resource: No" +size_flags_vertical = 0 +text = "/some/very/long/source/path/to/test/field" +editable = false +script = ExtResource( 1 ) diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/aseprite_imports_manager.gd b/hexmapper/addons/AsepriteWizard/interface/imports_manager/aseprite_imports_manager.gd new file mode 100644 index 0000000..731aba2 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/aseprite_imports_manager.gd @@ -0,0 +1,5 @@ +@tool +extends Window + +func _on_close_requested(): + self.queue_free() diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/aseprite_imports_manager.gd.uid b/hexmapper/addons/AsepriteWizard/interface/imports_manager/aseprite_imports_manager.gd.uid new file mode 100644 index 0000000..e07941a --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/aseprite_imports_manager.gd.uid @@ -0,0 +1 @@ +uid://7njyc08k32tu diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/aseprite_imports_manager.tscn b/hexmapper/addons/AsepriteWizard/interface/imports_manager/aseprite_imports_manager.tscn new file mode 100644 index 0000000..444e93b --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/aseprite_imports_manager.tscn @@ -0,0 +1,14 @@ +[gd_scene load_steps=2 format=3 uid="uid://0x3mlxsex7eb"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/imports_manager/aseprite_imports_manager.gd" id="1_wrm15"] + +[node name="AsepriteDockImportsWindow" type="Window"] +title = "Aseprite Imports Manager" +initial_position = 1 +size = Vector2i(612, 458) +wrap_controls = true +transient = true +min_size = Vector2i(600, 400) +script = ExtResource("1_wrm15") + +[connection signal="close_requested" from="." to="." method="_on_close_requested"] diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/dock_imports_panel.gd b/hexmapper/addons/AsepriteWizard/interface/imports_manager/dock_imports_panel.gd new file mode 100644 index 0000000..2d40223 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/dock_imports_panel.gd @@ -0,0 +1,330 @@ +@tool +extends Panel + +const wizard_config = preload("../../config/wizard_config.gd") + +var _import_helper = preload("./import_helper.gd").new() + +@onready var _tree_container = $MarginContainer/VBoxContainer/HSplitContainer/tree +@onready var _resource_tree = _tree_container.get_resource_tree() +@onready var _details = $MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer + +@onready var _nothing_container = $MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer/nothing +@onready var _single_item_container = $MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer/single_item +@onready var _multiple_items_container = $MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer/multiple_items + +@onready var _confirmation_warning_container = $MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer/confirmation_warning + +const supported_types = [ + "Sprite2D", + "Sprite3D", + "AnimatedSprite2D", + "AnimatedSprite3D", + "TextureRect", +] + +var _selection_count = 0 +var _current_buttons_container +var _resources_to_process + +var _should_save_in = 0 + + +func _ready(): + _set_empty_details_state() + + var file_tree = _get_file_tree("res://") + _setup_tree(file_tree) + + +# Unfortunately godot throws some nasty warnings when trying to save after +# multiple import operations. I implemented this late save as a workaround +func _process(delta): + if _should_save_in > 0: + _should_save_in -= delta + if _should_save_in <= 0: + _should_save_in = 0 + _save_all_scenes() + + +func _get_file_tree(base_path: String, dir_name: String = "") -> Dictionary: + var dir_path = base_path.path_join(dir_name) + var dir = DirAccess.open(dir_path) + var dir_data = { "path": dir_path, "name": dir_name, "children": [], "type": "dir", } + if not dir: + return dir_data + + dir.list_dir_begin() + var file_name = dir.get_next() + + while file_name != "": + if dir.current_is_dir() and _is_importable_folder(dir_path, file_name): + var child_data = _get_file_tree(dir_path, file_name) + if not child_data.children.is_empty(): + dir_data.children.push_back(child_data) + elif file_name.ends_with(".tscn"): + var file_path = dir_path.path_join(file_name) + var metadata = _get_aseprite_metadata(file_path) + if not metadata.is_empty(): + dir_data.children.push_back({ + "name": file_name, + "path": file_path, + "resources": metadata, + "type": "file", + }) + + file_name = dir.get_next() + + return dir_data + + +func _is_importable_folder(dir_path: String, dir_name: String) -> bool: + return dir_path != "res://" or dir_name != "addons" + + +func _setup_tree(resource_tree: Dictionary) -> void: + _resource_tree.set_column_title(0, "Resource") + + var root = _resource_tree.create_item() + + _add_items_to_tree(root, resource_tree.children) + + +func _add_items_to_tree(root: TreeItem, children: Array): + for node in children: + var item: TreeItem = _resource_tree.create_item(root) + item.set_text(0, node.name) + item.set_meta("node", node) + match node.type: + "dir": + item.set_icon(0, get_theme_icon("Folder", "EditorIcons")) + _add_items_to_tree(item, node.children) + + "file": + item.set_icon(0, get_theme_icon("PackedScene", "EditorIcons")) + _add_items_to_tree(item, node.resources) + + "resource": + item.set_icon(0, get_theme_icon(node.node_type, "EditorIcons")) + if node.has_changes: + item.set_text(0, "%s (*)" % node.name) + + +func _get_aseprite_metadata(file_path: String) -> Array: + var scene: PackedScene = load(file_path) + var root = scene.instantiate() + var state = scene.get_state() + + var resources = [] + for i in range(state.get_node_count()): + var node_type = state.get_node_type(i) + if _is_supported_type(node_type): + var node_path = state.get_node_path(i) + var target_node = root.get_node(node_path) + var meta = wizard_config.load_config(target_node) + if meta != null: + resources.push_back({ + "type": "resource", + "node_type": node_type, + "name": node_path, + "node_path": node_path, + "node_name": state.get_node_name(i), + "meta": meta, + "scene_path": file_path, + "has_changes": _has_source_changes(target_node, meta.get("source", "")) + }) + + return resources + + +func _has_source_changes(target_node: Node, source_path: String) -> bool: + if not source_path or source_path == "": + return false + var saved_hash = wizard_config.get_source_hash(target_node) + if saved_hash == "": + return false + var current_hash = FileAccess.get_md5(source_path) + + return saved_hash != current_hash + + +func _is_supported_type(node_type: String) -> bool: + return supported_types.has(node_type) + + +func _open_scene(item: TreeItem) -> void: + var meta = item.get_meta("node") + if meta: + EditorInterface.open_scene_from_path(meta.path) + + +func _trigger_import(meta: Dictionary) -> void: + # A more elegant way would have been to change the PackedScene directly, however + # during my attempts changing external resources this way was buggy. I decided + # to open and edit the scene via editor with the caveat of having to keep it open afterwards. + EditorInterface.open_scene_from_path(meta.scene_path) + + var root_node = EditorInterface.get_edited_scene_root() + + if not root_node: + printerr("couldn´t open scene %s" % meta.scene_path) + + await _import_helper.import_node(root_node, meta) + + print("Import complete: %s (%s) node from %s" % [ meta.node_path, meta.meta.source, meta.scene_path]) + + +func _on_resource_tree_multi_selected(_item: TreeItem, _column: int, selected: bool) -> void: + _confirmation_warning_container.hide() + _resources_to_process = null + if _current_buttons_container != null: + _current_buttons_container.show_buttons() + + if selected: + _selection_count += 1 + else: + _selection_count -= 1 + + _nothing_container.hide() + _single_item_container.hide() + _multiple_items_container.hide() + + match _selection_count: + 0: + _nothing_container.show() + 1: + _single_item_container.show() + _set_item_details(_resource_tree.get_selected()) + _current_buttons_container = _single_item_container + _: + _multiple_items_container.show() + _multiple_items_container.set_selected_count(_selection_count) + _current_buttons_container = _multiple_items_container + + +func _set_item_details(item: TreeItem) -> void: + if not item.has_meta("node"): + return + var data = item.get_meta("node") + _single_item_container.set_resource_details(data) + + +func _on_multiple_items_import_triggered(): + var selected_item = _resource_tree.get_next_selected(null) + var all_resources = [] + var scenes_to_open = 0 + + while selected_item != null: + scenes_to_open += _set_all_resources(selected_item.get_meta("node"), all_resources) + selected_item = _resource_tree.get_next_selected(selected_item) + + _resources_to_process = all_resources + _show_confirmation_message(scenes_to_open, all_resources.size()) + + +func _on_single_item_import_triggered(): + var selected = _resource_tree.get_selected() + var meta = selected.get_meta("node") + + if meta.type == "resource": + await _trigger_import(_resource_tree.get_selected().get_meta("node")) + _set_tree_item_as_saved(_resource_tree.get_selected()) + _single_item_container.hide_source_change_warning() + EditorInterface.save_scene() + else: + var selected_item = _resource_tree.get_selected() + var all_resources = [] + var scenes_to_open = _set_all_resources(selected_item.get_meta("node"), all_resources) + _resources_to_process = all_resources + _show_confirmation_message(scenes_to_open, all_resources.size()) + + +func _on_single_item_open_scene_triggered(): + var selected_item = _resource_tree.get_selected() + var meta = selected_item.get_meta("node") + if meta.type == "file": + EditorInterface.open_scene_from_path(meta.path) + else: + EditorInterface.open_scene_from_path(meta.scene_path) + + +func _set_all_resources(meta: Dictionary, resources: Array): + var scenes_to_open = 0 + match meta.type: + "dir": + for c in meta.children: + scenes_to_open += _set_all_resources(c, resources) + "file": + scenes_to_open += 1 + for r in meta.resources: + if not resources.has(r): + resources.push_back(r) + "resource": + if not resources.has(meta): + resources.push_back(meta) + return scenes_to_open + + +func _save_all_scenes(): + EditorInterface.save_all_scenes() + _reload_tree() + + +func _show_confirmation_message(scenes: int, resources: int): + _current_buttons_container.hide_buttons() + if scenes > 1: + _confirmation_warning_container.set_message("You are about to open %s scenes and re-import %s resources. Do you wish to continue?" % [scenes, resources]) + else: + _confirmation_warning_container.set_message("You are about to re-import %s resources. Do you wish to continue?" % resources) + + _confirmation_warning_container.show() + + +func _on_resource_tree_refresh_triggered(): + _set_empty_details_state() + _reload_tree() + + +func _reload_tree(): + _confirmation_warning_container.hide() + _resources_to_process = null + if _current_buttons_container != null: + _current_buttons_container.show_buttons() + _current_buttons_container = null + + _selection_count = 0 + _resource_tree.clear() + var file_tree = _get_file_tree("res://") + _setup_tree(file_tree) + + +func _set_empty_details_state(): + _nothing_container.show() + _single_item_container.hide() + _multiple_items_container.hide() + _confirmation_warning_container.hide() + + +func _set_tree_item_as_saved(item: TreeItem) -> void: + var meta = item.get_meta("node") + meta.has_changes = false + item.set_meta("node", meta) + item.set_text(0, meta.name) + + +func _on_confirmation_warning_warning_confirmed(): + _confirmation_warning_container.hide() + _current_buttons_container.show_buttons() + + for resource in _resources_to_process: + await _trigger_import(resource) + EditorInterface.mark_scene_as_unsaved() + _resources_to_process = null + + _should_save_in = 1 + + +func _on_confirmation_warning_warning_declined(): + _confirmation_warning_container.hide() + _current_buttons_container.show_buttons() + _resources_to_process = null diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/dock_imports_panel.gd.uid b/hexmapper/addons/AsepriteWizard/interface/imports_manager/dock_imports_panel.gd.uid new file mode 100644 index 0000000..378ec00 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/dock_imports_panel.gd.uid @@ -0,0 +1 @@ +uid://dseoyxh1qlb0a diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/dock_imports_panel.tscn b/hexmapper/addons/AsepriteWizard/interface/imports_manager/dock_imports_panel.tscn new file mode 100644 index 0000000..40407f6 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/dock_imports_panel.tscn @@ -0,0 +1,87 @@ +[gd_scene load_steps=7 format=3 uid="uid://ci67r2f2btg5"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/imports_manager/dock_imports_panel.gd" id="1_1xyeb"] +[ext_resource type="PackedScene" uid="uid://cisgsfvp4nf1g" path="res://addons/AsepriteWizard/interface/shared/tree/resource_tree.tscn" id="2_d1s4o"] +[ext_resource type="PackedScene" uid="uid://qgmln507kjnm" path="res://addons/AsepriteWizard/interface/shared/tree/tree_selection_confirmation_warning.tscn" id="3_2us73"] +[ext_resource type="PackedScene" uid="uid://dnlk2yep7teea" path="res://addons/AsepriteWizard/interface/imports_manager/tree_selection_single_item.tscn" id="3_4ufqa"] +[ext_resource type="PackedScene" uid="uid://bhtu6mlwmthqo" path="res://addons/AsepriteWizard/interface/imports_manager/tree_selection_multiple_items.tscn" id="3_pw8ds"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_edrvq"] + +[node name="dock_imports" type="Panel"] +custom_minimum_size = Vector2(600, 400) +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 +theme_override_styles/panel = SubResource("StyleBoxEmpty_edrvq") +script = ExtResource("1_1xyeb") + +[node name="MarginContainer" type="MarginContainer" parent="."] +custom_minimum_size = Vector2(400, 300) +layout_mode = 1 +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 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 + +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] +layout_mode = 2 + +[node name="HSplitContainer" type="HSplitContainer" parent="MarginContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="tree" parent="MarginContainer/VBoxContainer/HSplitContainer" instance=ExtResource("2_d1s4o")] +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/HSplitContainer"] +custom_minimum_size = Vector2(200, 0) +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/HSplitContainer/MarginContainer"] +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer/MarginContainer"] +layout_mode = 2 +text = "Details" +horizontal_alignment = 1 + +[node name="HSeparator" type="HSeparator" parent="MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="nothing" type="Label" parent="MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 6 +text = "Nothing selected" +horizontal_alignment = 1 + +[node name="single_item" parent="MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer" instance=ExtResource("3_4ufqa")] +layout_mode = 2 + +[node name="multiple_items" parent="MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer" instance=ExtResource("3_pw8ds")] +layout_mode = 2 + +[node name="confirmation_warning" parent="MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer" instance=ExtResource("3_2us73")] +layout_mode = 2 + +[connection signal="multi_selected" from="MarginContainer/VBoxContainer/HSplitContainer/tree" to="." method="_on_resource_tree_multi_selected"] +[connection signal="refresh_triggered" from="MarginContainer/VBoxContainer/HSplitContainer/tree" to="." method="_on_resource_tree_refresh_triggered"] +[connection signal="import_triggered" from="MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer/single_item" to="." method="_on_single_item_import_triggered"] +[connection signal="open_scene_triggered" from="MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer/single_item" to="." method="_on_single_item_open_scene_triggered"] +[connection signal="import_triggered" from="MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer/multiple_items" to="." method="_on_multiple_items_import_triggered"] +[connection signal="warning_confirmed" from="MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer/confirmation_warning" to="." method="_on_confirmation_warning_warning_confirmed"] +[connection signal="warning_declined" from="MarginContainer/VBoxContainer/HSplitContainer/MarginContainer/VBoxContainer/confirmation_warning" to="." method="_on_confirmation_warning_warning_declined"] diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/import_helper.gd b/hexmapper/addons/AsepriteWizard/interface/imports_manager/import_helper.gd new file mode 100644 index 0000000..178ae1f --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/import_helper.gd @@ -0,0 +1,140 @@ +@tool +extends RefCounted + +const wizard_config = preload("../../config/wizard_config.gd") +const result_code = preload("../../config/result_codes.gd") + +var _sprite_animation_creator = preload("../../creators/animation_player/sprite_animation_creator.gd").new() +var _texture_rect_animation_creator = preload("../../creators/animation_player/texture_rect_animation_creator.gd").new() +var _static_texture_creator = preload("../../creators/static_texture/texture_creator.gd").new() +var _sprite_frames_creator = preload("../../creators/sprite_frames/sprite_frames_creator.gd").new() +var _aseprite_file_exporter = preload("../../aseprite/file_exporter.gd").new() +var _config = preload("../../config/config.gd").new() + + +func import_node(root_node: Node, meta: Dictionary) -> void: + var node = root_node.get_node(meta.node_path) + + if node == null: + printerr("Node not found: %s" % meta.node_path) + return + + if node is AnimatedSprite2D or node is AnimatedSprite3D: + await _sprite_frames_import(node, meta) + else: + await _animation_import(node, root_node, meta) + + +func _sprite_frames_import(node: Node, resource_config: Dictionary) -> void: + var config = resource_config.meta + if not config.source: + printerr("Node config missing information.") + return + + var source = ProjectSettings.globalize_path(config.source) + var options = _parse_import_options(config, resource_config.scene_path.get_base_dir()) + + var aseprite_output = _aseprite_file_exporter.generate_aseprite_file(source, options) + + if not aseprite_output.is_ok: + printerr(result_code.get_error_message(aseprite_output.code)) + return + + EditorInterface.get_resource_filesystem().scan() + + await EditorInterface.get_resource_filesystem().filesystem_changed + + _sprite_frames_creator.create_animations(node, aseprite_output.content, { + "slice": options.slice, + "should_create_portable_texture": config.get("embed_tex", false), + "should_round_fps": config.get("should_round_fps", true), + }) + + wizard_config.set_source_hash(node, FileAccess.get_md5(source)) + _handle_cleanup(aseprite_output.content, config.get("embed_tex", false)) + + +func _animation_import(node: Node, root_node: Node, resource_config: Dictionary) -> void: + if not resource_config.meta.source: + printerr("Node config missing information.") + return + + if resource_config.meta.get("i_mode", 0) == 0: + await _import_to_animation_player(node, root_node, resource_config) + else: + await _import_static(node, resource_config) + + +func _import_to_animation_player(node: Node, root: Node, resource_config: Dictionary) -> void: + var config = resource_config.meta + var source = ProjectSettings.globalize_path(config.source) + var options = _parse_import_options(config, resource_config.scene_path.get_base_dir()) + + var aseprite_output = _aseprite_file_exporter.generate_aseprite_file(source, options) + if not aseprite_output.is_ok: + printerr(result_code.get_error_message(aseprite_output.code)) + return + + EditorInterface.get_resource_filesystem().scan() + await EditorInterface.get_resource_filesystem().filesystem_changed + + var anim_options = { + "keep_anim_length": config.keep_anim_length, + "cleanup_hide_unused_nodes": config.get("set_vis_track"), + "slice": config.get("slice", ""), + "should_create_portable_texture": config.get("embed_tex", false), + } + var animation_creator = _texture_rect_animation_creator if node is TextureRect else _sprite_animation_creator + + animation_creator.create_animations(node, root.get_node(config.player), aseprite_output.content, anim_options) + + wizard_config.set_source_hash(node, FileAccess.get_md5(source)) + _handle_cleanup(aseprite_output.content, config.get("embed_tex", false)) + + +func _import_static(node: Node, resource_config: Dictionary) -> void: + var config = resource_config.meta + var source = ProjectSettings.globalize_path(config.source) + var options = _parse_import_options(config, resource_config.scene_path.get_base_dir()) + options["first_frame_only"] = true + + var aseprite_output = _aseprite_file_exporter.generate_aseprite_file(source, options) + + if not aseprite_output.is_ok: + printerr(result_code.get_error_message(aseprite_output.code)) + return + + EditorInterface.get_resource_filesystem().scan() + await EditorInterface.get_resource_filesystem().filesystem_changed + + _static_texture_creator.load_texture(node, aseprite_output.content, { + "slice": options.slice, + "should_create_portable_texture": config.get("embed_tex", false), + }) + + wizard_config.set_source_hash(node, FileAccess.get_md5(source)) + _handle_cleanup(aseprite_output.content, config.get("embed_tex", false) ) + + +func _parse_import_options(config: Dictionary, scene_base_path: String) -> Dictionary: + return { + "output_folder": config.o_folder if config.o_folder != "" else scene_base_path, + "exception_pattern": config.o_ex_p, + "only_visible_layers": config.only_visible, + "output_filename": config.o_name, + "layer": config.get("layer"), + "layers": config.get("layers", []), + "slice": config.get("slice", "") + } + + +func _handle_cleanup(aseprite_content, should_remove_spritesheet: bool): + if _config.should_remove_source_files(): + DirAccess.remove_absolute(aseprite_content.data_file) + if should_remove_spritesheet: + DirAccess.remove_absolute(aseprite_content.sprite_sheet) + var import_file = "%s.import" % aseprite_content.sprite_sheet + if FileAccess.file_exists(import_file): + DirAccess.remove_absolute(import_file) + + EditorInterface.get_resource_filesystem().scan() diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/import_helper.gd.uid b/hexmapper/addons/AsepriteWizard/interface/imports_manager/import_helper.gd.uid new file mode 100644 index 0000000..cd2a691 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/import_helper.gd.uid @@ -0,0 +1 @@ +uid://cdd8xhuk0b8hk diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/import_panels.gd b/hexmapper/addons/AsepriteWizard/interface/imports_manager/import_panels.gd new file mode 100644 index 0000000..c972dd5 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/import_panels.gd @@ -0,0 +1,28 @@ +@tool +extends MarginContainer + +signal dock_requested + +enum Tabs { + DOCK_IMPORTS = 0, +} + +@onready var _tabs: TabContainer = $TabContainer +@onready var _dock_button: Button = $dock_button + +func _ready(): + _tabs.set_tab_title(Tabs.DOCK_IMPORTS, "Dock Imports") + _dock_button.icon = get_theme_icon("MakeFloating", "EditorIcons") + set_as_floating() + + +func _on_dock_button_pressed(): + dock_requested.emit() + + +func set_as_floating(): + _dock_button.tooltip_text = "Dock window" + + +func set_as_docked(): + _dock_button.tooltip_text = "Undock window" diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/import_panels.gd.uid b/hexmapper/addons/AsepriteWizard/interface/imports_manager/import_panels.gd.uid new file mode 100644 index 0000000..49f4fdc --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/import_panels.gd.uid @@ -0,0 +1 @@ +uid://5vlmnyc62f1j diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/import_panels.tscn b/hexmapper/addons/AsepriteWizard/interface/imports_manager/import_panels.tscn new file mode 100644 index 0000000..2083f3d --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/import_panels.tscn @@ -0,0 +1,42 @@ +[gd_scene load_steps=5 format=3 uid="uid://bae2rn6vwdx88"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/imports_manager/import_panels.gd" id="1_853ds"] +[ext_resource type="PackedScene" uid="uid://ci67r2f2btg5" path="res://addons/AsepriteWizard/interface/imports_manager/dock_imports_panel.tscn" id="2_rtubf"] + +[sub_resource type="Image" id="Image_47yuu"] +data = { +"data": PackedByteArray(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, 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, 1, 224, 224, 224, 82, 225, 225, 225, 126, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 114, 230, 230, 230, 30, 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, 225, 225, 225, 143, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 238, 229, 229, 229, 29, 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, 224, 224, 224, 242, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 113, 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, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 64, 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, 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, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 128, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 149, 149, 149, 24, 146, 146, 146, 112, 146, 146, 146, 128, 146, 146, 146, 128, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 128, 255, 255, 255, 0, 255, 255, 255, 0, 149, 149, 149, 24, 145, 145, 145, 231, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 128, 255, 255, 255, 0, 255, 255, 255, 0, 146, 146, 146, 112, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 128, 255, 255, 255, 0, 255, 255, 255, 0, 146, 146, 146, 128, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 128, 255, 255, 255, 0, 255, 255, 255, 0, 146, 146, 146, 128, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 128, 255, 255, 255, 0, 255, 255, 255, 0, 146, 146, 146, 128, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 128, 255, 255, 255, 0, 255, 255, 255, 0, 146, 146, 146, 128, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 128, 255, 255, 255, 0, 255, 255, 255, 0, 146, 146, 146, 128, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 220, 220, 220, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 112, 255, 255, 255, 0, 255, 255, 255, 0, 146, 146, 146, 128, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 189, 189, 189, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 237, 227, 227, 227, 27, 255, 255, 255, 0, 255, 255, 255, 0, 146, 146, 146, 128, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 170, 170, 170, 255, 185, 185, 185, 255, 184, 184, 184, 255, 184, 184, 184, 255, 184, 184, 184, 255, 184, 184, 184, 255, 184, 184, 184, 255, 184, 184, 184, 255, 184, 184, 184, 255, 184, 184, 184, 255, 184, 184, 184, 255, 224, 224, 224, 128, 224, 224, 224, 128, 224, 224, 224, 112, 227, 227, 227, 27, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 146, 146, 146, 128, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 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, 146, 146, 146, 128, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 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, 146, 146, 146, 128, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 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, 146, 146, 146, 112, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 239, 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, 149, 149, 149, 24, 145, 145, 145, 231, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 145, 145, 145, 255, 146, 146, 146, 126, 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, 149, 149, 149, 24, 145, 145, 145, 111, 146, 146, 146, 128, 146, 146, 146, 128, 146, 146, 146, 128, 146, 146, 146, 128, 146, 146, 146, 128, 146, 146, 146, 128, 146, 146, 146, 128, 146, 146, 146, 128, 146, 146, 146, 128, 146, 146, 146, 128, 146, 146, 146, 128, 146, 146, 146, 126, 145, 145, 145, 72, 255, 255, 255, 1, 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, 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": 24, +"mipmaps": false, +"width": 24 +} + +[sub_resource type="ImageTexture" id="ImageTexture_qam8x"] +image = SubResource("Image_47yuu") + +[node name="ImportPanels" 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 +script = ExtResource("1_853ds") + +[node name="TabContainer" type="TabContainer" parent="."] +layout_mode = 2 + +[node name="dock_imports" parent="TabContainer" instance=ExtResource("2_rtubf")] +layout_mode = 2 +metadata/_tab_name = "Dock Imports" + +[node name="dock_button" type="Button" parent="."] +layout_mode = 2 +size_flags_horizontal = 8 +size_flags_vertical = 0 +tooltip_text = "Dock window" +icon = SubResource("ImageTexture_qam8x") + +[connection signal="pressed" from="dock_button" to="." method="_on_dock_button_pressed"] diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_filter_field.gd b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_filter_field.gd new file mode 100644 index 0000000..51fa19b --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_filter_field.gd @@ -0,0 +1,22 @@ +@tool +extends LineEdit + +signal change_finished(text: String) + +@export var debounce_time_in_seconds: float = 0.3 + +var _time_since_last_change: float = 0.0 +var _has_pending_changes: bool = false + + +func _process(delta: float) -> void: + if _has_pending_changes: + _time_since_last_change += delta + if _time_since_last_change > debounce_time_in_seconds: + _has_pending_changes = false + change_finished.emit(self.text) + + +func _on_text_changed(_new_text: String) -> void: + _has_pending_changes = true + _time_since_last_change = 0 diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_filter_field.gd.uid b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_filter_field.gd.uid new file mode 100644 index 0000000..ee422c3 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_filter_field.gd.uid @@ -0,0 +1 @@ +uid://7rgda6mqi7x1 diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_multiple_items.gd b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_multiple_items.gd new file mode 100644 index 0000000..cf8882b --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_multiple_items.gd @@ -0,0 +1,22 @@ +@tool +extends VBoxContainer + +signal import_triggered + +@onready var _import_message = $message +@onready var _import_button = $buttons + +func set_selected_count(number_of_items: int) -> void: + _import_message.text = "%2d items selected" % number_of_items + + +func show_buttons(): + _import_button.show() + + +func hide_buttons(): + _import_button.hide() + + +func _on_import_selected_button_up(): + import_triggered.emit() diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_multiple_items.gd.uid b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_multiple_items.gd.uid new file mode 100644 index 0000000..b50995f --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_multiple_items.gd.uid @@ -0,0 +1 @@ +uid://b42m8paobx71r diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_multiple_items.tscn b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_multiple_items.tscn new file mode 100644 index 0000000..a59a220 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_multiple_items.tscn @@ -0,0 +1,25 @@ +[gd_scene load_steps=2 format=3 uid="uid://bhtu6mlwmthqo"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/imports_manager/tree_selection_multiple_items.gd" id="1_beamo"] + +[node name="multiple_items" type="VBoxContainer"] +visible = false +size_flags_vertical = 3 +script = ExtResource("1_beamo") + +[node name="message" type="Label" parent="."] +layout_mode = 2 +size_flags_vertical = 6 +text = "Multiple items selected +" +horizontal_alignment = 1 + +[node name="buttons" type="HFlowContainer" parent="."] +layout_mode = 2 + +[node name="import_selected" type="Button" parent="buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Re-Import all" + +[connection signal="button_up" from="buttons/import_selected" to="." method="_on_import_selected_button_up"] diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_single_item.gd b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_single_item.gd new file mode 100644 index 0000000..5d512df --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_single_item.gd @@ -0,0 +1,141 @@ +@tool +extends VBoxContainer + +signal import_triggered +signal open_scene_triggered + +@onready var _name = $GridContainer/name_value +@onready var _type = $GridContainer/type_value +@onready var _path = $GridContainer/path_value + +@onready var _source_label = $GridContainer/source_file_label +@onready var _source = $GridContainer/source_file_value +@onready var _layer_label = $GridContainer/layer_label +@onready var _layer = $GridContainer/layer_value +@onready var _slice_label = $GridContainer/slice_label +@onready var _slice = $GridContainer/slice_value + +@onready var _o_name_label = $GridContainer/o_name_label +@onready var _o_name = $GridContainer/o_name_value +@onready var _o_folder_label = $GridContainer/o_folder_label +@onready var _o_folder_value = $GridContainer/o_folder_value + + +@onready var _resource_buttons = $resource_buttons +@onready var _dir_buttons = $dir_buttons +@onready var _scene_buttons = $scene_buttons + +@onready var _source_change_warning = $source_changed_warning + +@onready var _resource_only_fields = [ + _source_label, + _source, + _layer_label, + _layer, + _slice_label, + _slice, + _o_name_label, + _o_name, + _o_folder_label, + _o_folder_value, + _source_change_warning, +] + +var _current_resource_type = "resource" +var _resource_config: Dictionary = {} + +func _ready(): + _source_change_warning.set_text("Source file changed since last import") + _source_change_warning.hide() + + +func set_resource_details(resource_details: Dictionary) -> void: + _resource_config = resource_details + _resource_buttons.hide() + _dir_buttons.hide() + _scene_buttons.hide() + _source_change_warning.hide() + + _current_resource_type = resource_details.type + match resource_details.type: + "dir": + _name.text = resource_details.name + _type.text = "Folder" + _path.text = resource_details.path + _hide_resource_fields() + _dir_buttons.show() + "file": + _name.text = resource_details.name + _type.text = "File" + _path.text = resource_details.path + _hide_resource_fields() + _scene_buttons.show() + "resource": + _name.text = resource_details.node_name + _type.text = resource_details.node_type + _path.text = resource_details.node_path + + var meta = resource_details.meta + _source.text = meta.source + _layer.text = "All" if meta.get("layer", "") == "" else meta.layer + _slice.text = "All" if meta.get("slice", "") == "" else meta.slice + + var folder = resource_details.scene_path.get_base_dir() if meta.get("o_folder", "") == "" else meta.o_folder + var file_name = "" if meta.get("o_name", "") == "" else meta.o_name + + if _layer.text != "All": + file_name += _layer.text + elif file_name == "": + file_name = meta.source.get_basename().get_file() + _o_name.text = "%s/%s.png" % [folder, file_name] + + _show_resource_fields() + _resource_buttons.show() + + _source_change_warning.visible = resource_details.has_changes + + +func _hide_resource_fields(): + for f in _resource_only_fields: + f.hide() + + +func _show_resource_fields(): + for f in _resource_only_fields: + f.show() + + +func show_buttons(): + match _current_resource_type: + "resource": + _resource_buttons.show() + "scene": + _scene_buttons.show() + _: + _dir_buttons.show() + + +func hide_buttons(): + _resource_buttons.hide() + _dir_buttons.hide() + _scene_buttons.hide() + + +func hide_source_change_warning(): + _source_change_warning.hide() + + +func _on_show_dir_in_fs_button_up(): + EditorInterface.get_file_system_dock().navigate_to_path(_path.text) + + +func _on_import_all_button_up(): + import_triggered.emit() + + +func _on_import_button_up(): + import_triggered.emit() + + +func _on_open_scene_button_up(): + open_scene_triggered.emit() diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_single_item.gd.uid b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_single_item.gd.uid new file mode 100644 index 0000000..e0b248c --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_single_item.gd.uid @@ -0,0 +1 @@ +uid://clux7vfxxsjof diff --git a/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_single_item.tscn b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_single_item.tscn new file mode 100644 index 0000000..914b180 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/imports_manager/tree_selection_single_item.tscn @@ -0,0 +1,158 @@ +[gd_scene load_steps=3 format=3 uid="uid://dnlk2yep7teea"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/imports_manager/tree_selection_single_item.gd" id="1_bb3ui"] +[ext_resource type="PackedScene" uid="uid://c1l0bk12iwln3" path="res://addons/AsepriteWizard/interface/shared/tree/inline_warning_panel.tscn" id="2_weuqf"] + +[node name="single_item" type="VBoxContainer"] +visible = false +script = ExtResource("1_bb3ui") + +[node name="GridContainer" type="GridContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +theme_override_constants/h_separation = 10 +columns = 2 + +[node name="type_label" type="Label" parent="GridContainer"] +layout_mode = 2 +size_flags_vertical = 0 +text = "Type" + +[node name="type_value" type="Label" parent="GridContainer"] +layout_mode = 2 +text = "-" + +[node name="name_label" type="Label" parent="GridContainer"] +layout_mode = 2 +size_flags_vertical = 0 +text = "Name" + +[node name="name_value" type="Label" parent="GridContainer"] +custom_minimum_size = Vector2(50, 0) +layout_mode = 2 +size_flags_horizontal = 3 +text = "-" +autowrap_mode = 2 + +[node name="path_label" type="Label" parent="GridContainer"] +layout_mode = 2 +size_flags_vertical = 0 +text = "Path" + +[node name="path_value" type="Label" parent="GridContainer"] +custom_minimum_size = Vector2(50, 0) +layout_mode = 2 +size_flags_horizontal = 3 +text = "-" +autowrap_mode = 1 + +[node name="HSeparator" type="HSeparator" parent="GridContainer"] +layout_mode = 2 + +[node name="HSeparator2" type="HSeparator" parent="GridContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="source_file_label" type="Label" parent="GridContainer"] +layout_mode = 2 +size_flags_vertical = 0 +text = "Aseprite File" + +[node name="source_file_value" type="Label" parent="GridContainer"] +custom_minimum_size = Vector2(50, 0) +layout_mode = 2 +size_flags_horizontal = 3 +text = "-" +autowrap_mode = 1 + +[node name="layer_label" type="Label" parent="GridContainer"] +layout_mode = 2 +size_flags_vertical = 0 +text = "Layer" + +[node name="layer_value" type="Label" parent="GridContainer"] +layout_mode = 2 +text = "-" + +[node name="slice_label" type="Label" parent="GridContainer"] +layout_mode = 2 +size_flags_vertical = 0 +text = "Slice" + +[node name="slice_value" type="Label" parent="GridContainer"] +layout_mode = 2 +text = "-" + +[node name="o_folder_label" type="Label" parent="GridContainer"] +visible = false +layout_mode = 2 +size_flags_vertical = 0 +text = "Output folder" + +[node name="o_folder_value" type="Label" parent="GridContainer"] +visible = false +custom_minimum_size = Vector2(50, 0) +layout_mode = 2 +size_flags_horizontal = 3 +text = "-" + +[node name="o_name_label" type="Label" parent="GridContainer"] +layout_mode = 2 +size_flags_vertical = 0 +text = "Spritesheet name" + +[node name="o_name_value" type="Label" parent="GridContainer"] +layout_mode = 2 +text = "-" + +[node name="source_changed_warning" parent="." instance=ExtResource("2_weuqf")] +layout_mode = 2 + +[node name="resource_buttons" type="HFlowContainer" parent="."] +visible = false +layout_mode = 2 + +[node name="import" type="Button" parent="resource_buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Re-Import" + +[node name="open_scene" type="Button" parent="resource_buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Open Scene" + +[node name="scene_buttons" type="HFlowContainer" parent="."] +visible = false +layout_mode = 2 + +[node name="import_all" type="Button" parent="scene_buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Re-Import all" + +[node name="open_scene" type="Button" parent="scene_buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Open Scene" + +[node name="dir_buttons" type="HFlowContainer" parent="."] +visible = false +layout_mode = 2 + +[node name="import_all" type="Button" parent="dir_buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Re-Import all" + +[node name="show_dir_in_fs" type="Button" parent="dir_buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Show In FileSystem" + +[connection signal="button_up" from="resource_buttons/import" to="." method="_on_import_button_up"] +[connection signal="button_up" from="resource_buttons/open_scene" to="." method="_on_open_scene_button_up"] +[connection signal="button_up" from="scene_buttons/import_all" to="." method="_on_import_all_button_up"] +[connection signal="button_up" from="scene_buttons/open_scene" to="." method="_on_open_scene_button_up"] +[connection signal="button_up" from="dir_buttons/import_all" to="." method="_on_import_all_button_up"] +[connection signal="button_up" from="dir_buttons/show_dir_in_fs" to="." method="_on_show_dir_in_fs_button_up"] diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/animation_player_drop_button.gd b/hexmapper/addons/AsepriteWizard/interface/shared/animation_player_drop_button.gd new file mode 100644 index 0000000..dbcd0ac --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/animation_player_drop_button.gd @@ -0,0 +1,15 @@ +@tool +extends Button + +signal node_dropped(node_path) + +func _can_drop_data(_pos, data): + if data.type == "nodes": + var node = get_node(data.nodes[0]) + return node is AnimationPlayer + return false + + +func _drop_data(_pos, data): + var path = data.nodes[0] + node_dropped.emit(path) diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/animation_player_drop_button.gd.uid b/hexmapper/addons/AsepriteWizard/interface/shared/animation_player_drop_button.gd.uid new file mode 100644 index 0000000..401ca07 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/animation_player_drop_button.gd.uid @@ -0,0 +1 @@ +uid://dck4tbe6088uw diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/animation_player_drop_button.tscn b/hexmapper/addons/AsepriteWizard/interface/shared/animation_player_drop_button.tscn new file mode 100644 index 0000000..14148a5 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/animation_player_drop_button.tscn @@ -0,0 +1,12 @@ +[gd_scene load_steps=2 format=3 uid="uid://x1f1t87m582u"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/shared/animation_player_drop_button.gd" id="1_tfmxw"] + +[node name="options" type="OptionButton"] +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +item_count = 1 +selected = 0 +popup/item_0/text = "[empty]" +popup/item_0/id = 0 +script = ExtResource("1_tfmxw") diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/dir_drop_button.gd b/hexmapper/addons/AsepriteWizard/interface/shared/dir_drop_button.gd new file mode 100644 index 0000000..42c5489 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/dir_drop_button.gd @@ -0,0 +1,14 @@ +@tool +extends Button + +signal dir_dropped(path) + +func _can_drop_data(_pos, data): + if data.type == "files_and_dirs": + var dir_access = DirAccess.open(data.files[0]) + return dir_access != null + return false + + +func _drop_data(_pos, data): + dir_dropped.emit(data.files[0]) diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/dir_drop_button.gd.uid b/hexmapper/addons/AsepriteWizard/interface/shared/dir_drop_button.gd.uid new file mode 100644 index 0000000..3c31f85 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/dir_drop_button.gd.uid @@ -0,0 +1 @@ +uid://cl650ut7ogmai diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/dir_drop_button.tscn b/hexmapper/addons/AsepriteWizard/interface/shared/dir_drop_button.tscn new file mode 100644 index 0000000..332d3cc --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/dir_drop_button.tscn @@ -0,0 +1,10 @@ +[gd_scene load_steps=2 format=3 uid="uid://cwvgnm3o7eed2"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/shared/dir_drop_button.gd" id="1_7uqph"] + +[node name="button" type="Button"] +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "[empty]" +clip_text = true +script = ExtResource("1_7uqph") diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/source_drop_button.gd b/hexmapper/addons/AsepriteWizard/interface/shared/source_drop_button.gd new file mode 100644 index 0000000..3fdeed2 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/source_drop_button.gd @@ -0,0 +1,15 @@ +@tool +extends Button + +signal aseprite_file_dropped(path) + +func _can_drop_data(_pos, data): + if data.type == "files": + var extension = data.files[0].get_extension() + return extension == "ase" or extension == "aseprite" + return false + + +func _drop_data(_pos, data): + var path = data.files[0] + aseprite_file_dropped.emit(path) diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/source_drop_button.gd.uid b/hexmapper/addons/AsepriteWizard/interface/shared/source_drop_button.gd.uid new file mode 100644 index 0000000..8b1ea7f --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/source_drop_button.gd.uid @@ -0,0 +1 @@ +uid://banh2rdgl8smk diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/source_drop_button.tscn b/hexmapper/addons/AsepriteWizard/interface/shared/source_drop_button.tscn new file mode 100644 index 0000000..dc0c25e --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/source_drop_button.tscn @@ -0,0 +1,10 @@ +[gd_scene load_steps=2 format=3 uid="uid://dj1uo3blocr8e"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/shared/source_drop_button.gd" id="1_smfgi"] + +[node name="source_drop_button" type="Button"] +size_flags_horizontal = 3 +size_flags_stretch_ratio = 2.0 +text = "[empty]" +clip_text = true +script = ExtResource("1_smfgi") diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/tree/inline_warning_panel.gd b/hexmapper/addons/AsepriteWizard/interface/shared/tree/inline_warning_panel.gd new file mode 100644 index 0000000..3678c65 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/tree/inline_warning_panel.gd @@ -0,0 +1,19 @@ +@tool +extends PanelContainer + +@onready var _message = $MarginContainer/HBoxContainer/Label + +func _ready(): + _configure_source_warning() + + +func _configure_source_warning(): + var sb = self.get_theme_stylebox("panel") + var color = EditorInterface.get_editor_settings().get_setting("interface/theme/accent_color") + color.a = 0.2 + sb.bg_color = color + self.get_node("MarginContainer/HBoxContainer/Icon").texture = get_theme_icon("NodeInfo", "EditorIcons") + + +func set_text(text: String): + _message.text = text diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/tree/inline_warning_panel.gd.uid b/hexmapper/addons/AsepriteWizard/interface/shared/tree/inline_warning_panel.gd.uid new file mode 100644 index 0000000..c38d7eb --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/tree/inline_warning_panel.gd.uid @@ -0,0 +1 @@ +uid://ddax7id1ucbup diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/tree/inline_warning_panel.tscn b/hexmapper/addons/AsepriteWizard/interface/shared/tree/inline_warning_panel.tscn new file mode 100644 index 0000000..9a61018 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/tree/inline_warning_panel.tscn @@ -0,0 +1,51 @@ +[gd_scene load_steps=5 format=3 uid="uid://c1l0bk12iwln3"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/shared/tree/inline_warning_panel.gd" id="1_aomsj"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_rpkoa"] +bg_color = Color(0.44, 0.73, 0.98, 0.2) +border_width_left = 10 +border_color = Color(0.8, 0.8, 0.8, 0) +corner_radius_top_left = 5 +corner_radius_top_right = 5 +corner_radius_bottom_right = 5 +corner_radius_bottom_left = 5 + +[sub_resource type="Image" id="Image_6c2qv"] +data = { +"data": PackedByteArray(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, 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, 43, 255, 255, 255, 78, 255, 255, 255, 112, 255, 255, 255, 111, 255, 255, 255, 78, 255, 255, 255, 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, 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, 12, 255, 255, 255, 107, 255, 255, 255, 212, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 210, 255, 255, 255, 105, 255, 255, 255, 10, 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, 47, 255, 255, 255, 219, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 217, 255, 255, 255, 44, 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, 84, 255, 255, 255, 247, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 245, 255, 255, 255, 80, 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, 45, 255, 255, 255, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 244, 255, 255, 255, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 10, 255, 255, 255, 217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 216, 255, 255, 255, 10, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 104, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 101, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 211, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 207, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 44, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 39, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 81, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 255, 255, 255, 128, 255, 255, 255, 128, 255, 255, 255, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 76, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 114, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 110, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 114, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 109, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 81, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 75, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 43, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 37, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 210, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 204, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 104, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 97, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 10, 255, 255, 255, 217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 212, 255, 255, 255, 8, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 44, 255, 255, 255, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 242, 255, 255, 255, 39, 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, 81, 255, 255, 255, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 243, 255, 255, 255, 75, 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, 44, 255, 255, 255, 217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 214, 255, 255, 255, 41, 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, 10, 255, 255, 255, 102, 255, 255, 255, 208, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 207, 255, 255, 255, 100, 255, 255, 255, 9, 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, 38, 255, 255, 255, 75, 255, 255, 255, 110, 255, 255, 255, 110, 255, 255, 255, 75, 255, 255, 255, 38, 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, 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": 24, +"mipmaps": false, +"width": 24 +} + +[sub_resource type="ImageTexture" id="ImageTexture_7t6c7"] +image = SubResource("Image_6c2qv") + +[node name="inline_warning_panel" type="PanelContainer"] +visible = false +theme_override_styles/panel = SubResource("StyleBoxFlat_rpkoa") +script = ExtResource("1_aomsj") + +[node name="MarginContainer" type="MarginContainer" parent="."] +layout_mode = 2 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_right = 10 + +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"] +layout_mode = 2 + +[node name="Icon" type="TextureRect" parent="MarginContainer/HBoxContainer"] +modulate = Color(1, 1, 1, 0.486275) +custom_minimum_size = Vector2(16, 0) +layout_mode = 2 +texture = SubResource("ImageTexture_7t6c7") +stretch_mode = 5 + +[node name="Label" type="Label" parent="MarginContainer/HBoxContainer"] +custom_minimum_size = Vector2(10, 0) +layout_mode = 2 +size_flags_horizontal = 3 +text = "Source file changed since last import" +autowrap_mode = 2 diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/tree/resource_tree.gd b/hexmapper/addons/AsepriteWizard/interface/shared/tree/resource_tree.gd new file mode 100644 index 0000000..38d32d9 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/tree/resource_tree.gd @@ -0,0 +1,55 @@ +@tool +extends VBoxContainer + +signal refresh_triggered +signal multi_selected(item: TreeItem, column: int, selected: bool) + +@onready var _tree: Tree = $Tree + +func _on_tree_filter_change_finished(text): + var tree_root: TreeItem = _tree.get_root() + + if text == "": + tree_root.call_recursive("set", "visible", true) + return + tree_root.call_recursive("set", "visible", false) + + _make_matching_children_visible(tree_root, text.to_lower()) + + +func _make_matching_children_visible(tree_root: TreeItem, text: String) -> void: + for c in tree_root.get_children(): + if c.get_text(0).to_lower().contains(text): + c.visible = true + _ensure_parent_visible(c) + _make_matching_children_visible(c, text) + + +func _ensure_parent_visible(tree_item: TreeItem) -> void: + var node_parent = tree_item.get_parent() + if node_parent != null and not node_parent.visible: + node_parent.visible = true + _ensure_parent_visible(node_parent) + + +func _on_expand_all_pressed(): + var tree_root: TreeItem = _tree.get_root() + tree_root.set_collapsed_recursive(false) + + +func _on_collapse_all_pressed(): + var tree_root: TreeItem = _tree.get_root() + tree_root.set_collapsed_recursive(true) + tree_root.collapsed = false + + +func _on_refresh_tree_pressed(): + refresh_triggered.emit() + + +func _on_tree_multi_selected(item: TreeItem, column: int, selected: bool): + multi_selected.emit(item, column, selected) + + +func get_resource_tree() -> Tree: + return _tree diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/tree/resource_tree.gd.uid b/hexmapper/addons/AsepriteWizard/interface/shared/tree/resource_tree.gd.uid new file mode 100644 index 0000000..ea7d220 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/tree/resource_tree.gd.uid @@ -0,0 +1 @@ +uid://daush8km7pkw4 diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/tree/resource_tree.tscn b/hexmapper/addons/AsepriteWizard/interface/shared/tree/resource_tree.tscn new file mode 100644 index 0000000..222694c --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/tree/resource_tree.tscn @@ -0,0 +1,51 @@ +[gd_scene load_steps=3 format=3 uid="uid://cisgsfvp4nf1g"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/shared/tree/resource_tree.gd" id="1_io4rc"] +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/imports_manager/tree_filter_field.gd" id="1_q7epo"] + +[node name="resource_tree" type="VBoxContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +script = ExtResource("1_io4rc") + +[node name="buttons" type="HFlowContainer" parent="."] +layout_mode = 2 + +[node name="tree_filter" type="LineEdit" parent="buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "Filter..." +clear_button_enabled = true +script = ExtResource("1_q7epo") + +[node name="expand_all" type="Button" parent="buttons"] +custom_minimum_size = Vector2(150, 0) +layout_mode = 2 +text = "Expand All" + +[node name="collapse_all" type="Button" parent="buttons"] +custom_minimum_size = Vector2(150, 0) +layout_mode = 2 +text = "Collapse All" + +[node name="refresh_tree" type="Button" parent="buttons"] +custom_minimum_size = Vector2(150, 0) +layout_mode = 2 +text = "Refresh Tree" + +[node name="Tree" type="Tree" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +hide_root = true +select_mode = 2 + +[connection signal="change_finished" from="buttons/tree_filter" to="." method="_on_tree_filter_change_finished"] +[connection signal="text_changed" from="buttons/tree_filter" to="buttons/tree_filter" method="_on_text_changed"] +[connection signal="pressed" from="buttons/expand_all" to="." method="_on_expand_all_pressed"] +[connection signal="pressed" from="buttons/collapse_all" to="." method="_on_collapse_all_pressed"] +[connection signal="pressed" from="buttons/refresh_tree" to="." method="_on_refresh_tree_pressed"] +[connection signal="multi_selected" from="Tree" to="." method="_on_tree_multi_selected"] diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/tree/tree_selection_confirmation_warning.gd b/hexmapper/addons/AsepriteWizard/interface/shared/tree/tree_selection_confirmation_warning.gd new file mode 100644 index 0000000..8086db1 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/tree/tree_selection_confirmation_warning.gd @@ -0,0 +1,18 @@ +@tool +extends VBoxContainer + +signal warning_confirmed +signal warning_declined + +@onready var _warning_message = $MarginContainer/warning_message + +func set_message(text: String) -> void: + _warning_message.text = text + + +func _on_confirm_button_up(): + warning_confirmed.emit() + + +func _on_cancel_button_up(): + warning_declined.emit() diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/tree/tree_selection_confirmation_warning.gd.uid b/hexmapper/addons/AsepriteWizard/interface/shared/tree/tree_selection_confirmation_warning.gd.uid new file mode 100644 index 0000000..03386cb --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/tree/tree_selection_confirmation_warning.gd.uid @@ -0,0 +1 @@ +uid://51oo78wy8nxx diff --git a/hexmapper/addons/AsepriteWizard/interface/shared/tree/tree_selection_confirmation_warning.tscn b/hexmapper/addons/AsepriteWizard/interface/shared/tree/tree_selection_confirmation_warning.tscn new file mode 100644 index 0000000..828f71a --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/interface/shared/tree/tree_selection_confirmation_warning.tscn @@ -0,0 +1,34 @@ +[gd_scene load_steps=2 format=3 uid="uid://qgmln507kjnm"] + +[ext_resource type="Script" path="res://addons/AsepriteWizard/interface/shared/tree/tree_selection_confirmation_warning.gd" id="1_7gtu1"] + +[node name="confirmation_warning" type="VBoxContainer"] +script = ExtResource("1_7gtu1") + +[node name="MarginContainer" type="MarginContainer" parent="."] +layout_mode = 2 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 + +[node name="warning_message" type="Label" parent="MarginContainer"] +custom_minimum_size = Vector2(100, 0) +layout_mode = 2 +autowrap_mode = 2 + +[node name="buttons" type="HFlowContainer" parent="."] +layout_mode = 2 + +[node name="confirm" type="Button" parent="buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Confirm" + +[node name="cancel" type="Button" parent="buttons"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Cancel" + +[connection signal="button_up" from="buttons/confirm" to="." method="_on_confirm_button_up"] +[connection signal="button_up" from="buttons/cancel" to="." method="_on_cancel_button_up"] diff --git a/hexmapper/addons/AsepriteWizard/plugin.cfg b/hexmapper/addons/AsepriteWizard/plugin.cfg new file mode 100644 index 0000000..5a6faf5 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Aseprite Wizard" +description="Import Aseprite files to Godot in many different ways." +author="Vinicius Gerevini" +version="9.0.0" +script="plugin.gd" diff --git a/hexmapper/addons/AsepriteWizard/plugin.gd b/hexmapper/addons/AsepriteWizard/plugin.gd new file mode 100644 index 0000000..a7b44e1 --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/plugin.gd @@ -0,0 +1,219 @@ +@tool +extends EditorPlugin + +# importers +const NoopImportPlugin = preload("importers/noop_import_plugin.gd") +const SpriteFramesImportPlugin = preload("importers/sprite_frames_import_plugin.gd") +const SpriteFramesSplitImportPlugin = preload("res://addons/AsepriteWizard/importers/sprite_frames_multiple_import_plugin.gd") +const TilesetTextureImportPlugin = preload("importers/tileset_texture_import_plugin.gd") +const TextureImportPlugin = preload("importers/static_texture_import_plugin.gd") +const TextureSplitImportPlugin = preload("res://addons/AsepriteWizard/importers/static_texture_multiple_import_plugin.gd") +const LayerSpriteFramesImportPlugin = preload("res://addons/AsepriteWizard/importers/split_layer_importers/layer_import_plugin.gd") +const LayerTextureImportPlugin = preload("res://addons/AsepriteWizard/importers/split_layer_importers/layer_texture_import_plugin.gd") +const FileSystemHelper = preload("importers/helpers/file_system_helper.gd") +# export +const ExportPlugin = preload("export/export_plugin.gd") +# interface +const ConfigDialog = preload('config/config_dialog.tscn') +const WizardWindow = preload("interface/docks/wizard/as_wizard_dock_container.tscn") +const AsepriteDockImportsWindow = preload('interface/imports_manager/aseprite_imports_manager.tscn') +const ImportsManagerPanels = preload('interface/imports_manager/import_panels.tscn') + +const AnimatedSpriteInspectorPlugin = preload("interface/docks/animated_sprite/inspector_plugin.gd") +const SpriteInspectorPlugin = preload("interface/docks/sprite/inspector_plugin.gd") + +const tool_menu_name = "Aseprite Wizard" +const menu_item_name = "Spritesheet Wizard Dock..." +const config_menu_item_name = "Config..." +const import_menu_item_name = "Imports Manager..." + +var config = preload("config/config.gd").new() +var window: TabContainer +var config_window: PopupPanel +var imports_list_window: Window +var imports_list_panel: MarginContainer +var export_plugin : EditorExportPlugin +var sprite_inspector_plugin: EditorInspectorPlugin +var animated_sprite_inspector_plugin: EditorInspectorPlugin + +var file_system_helper + +var _importers = [] + +var _is_import_list_docked = false + +func _enter_tree(): + _load_config() + _setup_menu_entries() + _setup_importer() + _setup_exporter() + _setup_animated_sprite_inspector_plugin() + _setup_sprite_inspector_plugin() + + +func _exit_tree(): + _disable_plugin() + + +func _disable_plugin(): + _remove_menu_entries() + _remove_importer() + _remove_exporter() + _remove_wizard_dock() + _remove_inspector_plugins() + + +func _load_config(): + config.initialize_project_settings() + + +func _setup_menu_entries(): + var submenu = PopupMenu.new() + add_tool_submenu_item(tool_menu_name, submenu) + submenu.add_item(menu_item_name) + submenu.add_item(import_menu_item_name) + submenu.add_item(config_menu_item_name) + submenu.index_pressed.connect(_on_tool_menu_pressed) + + +func _remove_menu_entries(): + remove_tool_menu_item(tool_menu_name) + + +func _setup_importer(): + file_system_helper = FileSystemHelper.new() + add_child(file_system_helper) + + _importers = [ + NoopImportPlugin.new(), + SpriteFramesImportPlugin.new(), + SpriteFramesSplitImportPlugin.new(file_system_helper), + TilesetTextureImportPlugin.new(), + TextureImportPlugin.new(), + TextureSplitImportPlugin.new(file_system_helper), + LayerSpriteFramesImportPlugin.new(), + LayerTextureImportPlugin.new(), + ] + + for i in _importers: + add_import_plugin(i) + + +func _remove_importer(): + for i in _importers: + remove_import_plugin(i) + + if file_system_helper != null: + file_system_helper.queue_free() + file_system_helper = null + + +func _setup_exporter(): + export_plugin = ExportPlugin.new() + add_export_plugin(export_plugin) + + +func _remove_exporter(): + remove_export_plugin(export_plugin) + + +func _setup_sprite_inspector_plugin(): + sprite_inspector_plugin = SpriteInspectorPlugin.new() + add_inspector_plugin(sprite_inspector_plugin) + + +func _setup_animated_sprite_inspector_plugin(): + animated_sprite_inspector_plugin = AnimatedSpriteInspectorPlugin.new() + add_inspector_plugin(animated_sprite_inspector_plugin) + + +func _remove_inspector_plugins(): + remove_inspector_plugin(sprite_inspector_plugin) + remove_inspector_plugin(animated_sprite_inspector_plugin) + + +func _remove_wizard_dock(): + if window: + remove_control_from_bottom_panel(window) + window.queue_free() + window = null + + +func _open_window(): + if window: + make_bottom_panel_item_visible(window) + return + + window = WizardWindow.instantiate() + window.connect("close_requested",Callable(self,"_on_window_closed")) + add_control_to_bottom_panel(window, "Aseprite Wizard") + make_bottom_panel_item_visible(window) + + +func _open_config_dialog(): + if is_instance_valid(config_window): + config_window.queue_free() + + config_window = ConfigDialog.instantiate() + get_editor_interface().get_base_control().add_child(config_window) + config_window.popup_centered() + + +func _open_import_list_dialog(): + if is_instance_valid(imports_list_window): + imports_list_window.queue_free() + + if is_instance_valid(imports_list_panel): + if _is_import_list_docked: + remove_control_from_bottom_panel(imports_list_panel) + _is_import_list_docked = false + imports_list_panel.queue_free() + imports_list_panel = null + + imports_list_panel = ImportsManagerPanels.instantiate() + imports_list_panel.dock_requested.connect(_on_import_list_dock_requested) + _create_imports_manager_window(imports_list_panel) + + +func _on_window_closed(): + if window: + remove_control_from_bottom_panel(window) + window.queue_free() + window = null + + +func _on_tool_menu_pressed(index): + match index: + 0: # wizard dock + _open_window() + 1: # imports + _open_import_list_dialog() + 2: # config + _open_config_dialog() + + +func _on_import_list_dock_requested(): + if _is_import_list_docked: + remove_control_from_bottom_panel(imports_list_panel) + _is_import_list_docked = false + _create_imports_manager_window(imports_list_panel) + imports_list_panel.show() + imports_list_panel.anchors_preset = Control.PRESET_FULL_RECT + imports_list_panel.size_flags_vertical = Control.SIZE_EXPAND_FILL + imports_list_panel.size_flags_horizontal = Control.SIZE_EXPAND_FILL + imports_list_panel.set_as_floating() + return + + _is_import_list_docked = true + imports_list_panel.set_as_docked() + imports_list_window.remove_child(imports_list_panel) + imports_list_window.queue_free() + add_control_to_bottom_panel(imports_list_panel, "Aseprite Imports Manager") + make_bottom_panel_item_visible(imports_list_panel) + + +func _create_imports_manager_window(panel: MarginContainer): + imports_list_window = AsepriteDockImportsWindow.instantiate() + imports_list_window.add_child(panel) + get_editor_interface().get_base_control().add_child(imports_list_window) + imports_list_window.popup_centered_ratio(0.5) diff --git a/hexmapper/addons/AsepriteWizard/plugin.gd.uid b/hexmapper/addons/AsepriteWizard/plugin.gd.uid new file mode 100644 index 0000000..f01b1ec --- /dev/null +++ b/hexmapper/addons/AsepriteWizard/plugin.gd.uid @@ -0,0 +1 @@ +uid://dtbef2dmavih7 diff --git a/hexmapper/addons/script-ide/LICENSE b/hexmapper/addons/script-ide/LICENSE new file mode 100644 index 0000000..ffc9cf2 --- /dev/null +++ b/hexmapper/addons/script-ide/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Marius Hanl + +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/hexmapper/addons/script-ide/README.md b/hexmapper/addons/script-ide/README.md new file mode 100644 index 0000000..5cfa4cb --- /dev/null +++ b/hexmapper/addons/script-ide/README.md @@ -0,0 +1,65 @@ +# Script IDE + +Transforms the Script UI into an IDE like UI. +Tabs are used for navigating between scripts. +The default Outline got an overhaul and now shows all members of the script (not just methods) with unique icons for faster navigation. +Enhanced keyboard navigation for Scripts and Outline. +Fast quick search functionality. +Quick function Override functionality. + +Features: +- Scripts are now shown as Tabs inside a TabContainer +- The Outline got an overhaul and shows more than just the methods of the script. It includes the following members with a unique icon: + - Classes (Red Square) + - Constants (Red Circle) + - Signals (Yellow) + - Export variables (Orange) + - (Static) Variables (Red) + - Engine callback functions (Blue) + - (Static) Functions (Green) + - Setter functions (Green circle, with an arrow inside it pointing to the right) + - Getter functions (Green circle, with an arrow inside it pointing to the left) +- All the different members of the script can be hidden or made visible again by the outline filter. This allows fine control what should be visible (e.g. only signals, (Godot) functions, ...) +- A `Right Click` enables only the clicked filter, another `Right Click` will enable all filters again +- The Outline can be opened in a Popup with a defined shortcut for quick navigation between methods +- You can navigate through the Outline with the `Arrow` keys (or `Page up/Page down`) and scroll to the selected item by pressing `ENTER` +- Scripts can be opened in a Popup with a defined shortcut or when clicking the three dots on the top right of the TabContainer for quick navigation between scripts +- The currently edited script is automatically selected in the Filesystem Dock +- Files can be quickly searched by the Quick Search Popup with `Shift`+`Shift` +- You can find and quickly override any method from your super classes with `Alt`+`Ins` +- The plugin is written with performance in mind, everything is very fast and works without any lags or stuttering + +Customization: +- The Outline is on the right side (can be changed to be on the left side again) +- The Outline can be toggled via `File -> Toggle Scripts Panel`. This will hide or show it +- The order in the Outline can be changed +- There is also the possibility to hide private members, this is all members starting with a `_` +- The Script ItemList is not visible by default, but can be made visible again + +All settings can be changed in the `Editor Settings` under `Plugin` -> `Script Ide`: +- `Open Outline Popup` = Shortcut to control how the Outline Popup should be triggered (default=CTRL+O or META+O) +- `Outline Position Right` = Flag to control whether the outline should be on the right or on the left side of the script editor (default=true) +- `Outline Order` = List which specifies the order of all different types in the Outline +- `Hide Private Members` = Flag to control whether private members (methods/variables/constants starting with '_') should be hidden in the Outline or not (default=false) +- `Open Script Popup` = Shortcut to control how the Script Popup should be triggered (default=CTRL+U or META+U) +- `Script List Visible` = Flag to control whether the script list should still be visible or not (above the outline) (default=false) +- `Script Tabs Visible` = Flag to control whether the script tabs should be visible or not (default=true) +- `Script Tabs Position Top` = Flag to control whether the script tabs should be on the top or on the bottom (default=true) +- `Auto Navigate in FileSystem Dock` = Flag to control whether the script that is currently edited should be automatically selected in the Filesystem Dock (default=true) +- `Open Quick Search Popup` = Shortcut to control how the Quick Search Popup should be triggered (default=Shift+Shift, double press behavior is hardcoded for now) +- `Open Override Popup` = Shortcut to control how the Override Popup should be triggered (default=Alt+Ins) +- `Cycle Tab forward` = Shortcut to cycle the script tabs in the forward direction (only works in the 'Script' Editor Tab) (default=CTRL+TAB) +- `Cycle Tab backward` = Shortcut to cycle the script tabs in the backward direction (only works in the 'Script' Editor Tab) (default=CTRL+SHIFT+TAB) +- All outline visibility settings + +![Example of the Outline](https://github.com/user-attachments/assets/1729cb2b-01ae-4365-b77a-45edcb94b978) + +![Example of the Outline Popup](https://github.com/user-attachments/assets/995c721f-9708-40d9-a4e8-57b1a99e9c29) + +![Example of the TabContainer Script ItemList Popup](https://github.com/user-attachments/assets/484d498c-bd1c-4c77-a693-ac31a8500fbe) + +![Example of the Script ItemList Popup](https://github.com/user-attachments/assets/bb976604-6049-4ce1-a28e-377fc62899f6) + +![Example of the Quick Search Popup](https://github.com/user-attachments/assets/01141f05-e07c-4059-8d6f-e4c7490cbd40) + +![Example of the Plugin Editor Settings](https://github.com/user-attachments/assets/0450e423-bc49-4076-862b-c95a62190df1) diff --git a/hexmapper/addons/script-ide/icon/class.svg b/hexmapper/addons/script-ide/icon/class.svg new file mode 100644 index 0000000..12f44f7 --- /dev/null +++ b/hexmapper/addons/script-ide/icon/class.svg @@ -0,0 +1 @@ + diff --git a/hexmapper/addons/script-ide/icon/class.svg.import b/hexmapper/addons/script-ide/icon/class.svg.import new file mode 100644 index 0000000..4ff6f00 --- /dev/null +++ b/hexmapper/addons/script-ide/icon/class.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://csik7oxvt7tq3" +path="res://.godot/imported/class.svg-e6f2816a1f06041fb421c2af52817a4a.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/script-ide/icon/class.svg" +dest_files=["res://.godot/imported/class.svg-e6f2816a1f06041fb421c2af52817a4a.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=false diff --git a/hexmapper/addons/script-ide/icon/constant.svg b/hexmapper/addons/script-ide/icon/constant.svg new file mode 100644 index 0000000..8be4457 --- /dev/null +++ b/hexmapper/addons/script-ide/icon/constant.svg @@ -0,0 +1 @@ + diff --git a/hexmapper/addons/script-ide/icon/constant.svg.import b/hexmapper/addons/script-ide/icon/constant.svg.import new file mode 100644 index 0000000..2c2e17a --- /dev/null +++ b/hexmapper/addons/script-ide/icon/constant.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cawc456ja8vf5" +path="res://.godot/imported/constant.svg-f6e857276565573c7540f3c32801842a.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/script-ide/icon/constant.svg" +dest_files=["res://.godot/imported/constant.svg-f6e857276565573c7540f3c32801842a.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=false diff --git a/hexmapper/addons/script-ide/icon/engine_func.svg b/hexmapper/addons/script-ide/icon/engine_func.svg new file mode 100644 index 0000000..dee80a2 --- /dev/null +++ b/hexmapper/addons/script-ide/icon/engine_func.svg @@ -0,0 +1 @@ + diff --git a/hexmapper/addons/script-ide/icon/engine_func.svg.import b/hexmapper/addons/script-ide/icon/engine_func.svg.import new file mode 100644 index 0000000..fc9a323 --- /dev/null +++ b/hexmapper/addons/script-ide/icon/engine_func.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cupb0polhqrwj" +path="res://.godot/imported/engine_func.svg-91320e42f9cc7bdd7576002e82fa6ab8.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/script-ide/icon/engine_func.svg" +dest_files=["res://.godot/imported/engine_func.svg-91320e42f9cc7bdd7576002e82fa6ab8.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=false diff --git a/hexmapper/addons/script-ide/icon/export.svg b/hexmapper/addons/script-ide/icon/export.svg new file mode 100644 index 0000000..a8e8721 --- /dev/null +++ b/hexmapper/addons/script-ide/icon/export.svg @@ -0,0 +1 @@ + diff --git a/hexmapper/addons/script-ide/icon/export.svg.import b/hexmapper/addons/script-ide/icon/export.svg.import new file mode 100644 index 0000000..bb844d6 --- /dev/null +++ b/hexmapper/addons/script-ide/icon/export.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bvu2gnj8fv2kw" +path="res://.godot/imported/export.svg-d2d18132258a7a219ec1af1f0316c91c.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/script-ide/icon/export.svg" +dest_files=["res://.godot/imported/export.svg-d2d18132258a7a219ec1af1f0316c91c.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=false diff --git a/hexmapper/addons/script-ide/icon/func.svg b/hexmapper/addons/script-ide/icon/func.svg new file mode 100644 index 0000000..5388596 --- /dev/null +++ b/hexmapper/addons/script-ide/icon/func.svg @@ -0,0 +1 @@ + diff --git a/hexmapper/addons/script-ide/icon/func.svg.import b/hexmapper/addons/script-ide/icon/func.svg.import new file mode 100644 index 0000000..30cf4ff --- /dev/null +++ b/hexmapper/addons/script-ide/icon/func.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://rni04cl446ov" +path="res://.godot/imported/func.svg-139842caa5b4b7e4839711b6c756d0f7.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/script-ide/icon/func.svg" +dest_files=["res://.godot/imported/func.svg-139842caa5b4b7e4839711b6c756d0f7.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=false diff --git a/hexmapper/addons/script-ide/icon/func_get.svg b/hexmapper/addons/script-ide/icon/func_get.svg new file mode 100644 index 0000000..2fc6857 --- /dev/null +++ b/hexmapper/addons/script-ide/icon/func_get.svg @@ -0,0 +1 @@ + diff --git a/hexmapper/addons/script-ide/icon/func_get.svg.import b/hexmapper/addons/script-ide/icon/func_get.svg.import new file mode 100644 index 0000000..3c90423 --- /dev/null +++ b/hexmapper/addons/script-ide/icon/func_get.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c2a3aowyhxj5x" +path="res://.godot/imported/func_get.svg-093f0ce02889d1f102ff9cc3e7f72654.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/script-ide/icon/func_get.svg" +dest_files=["res://.godot/imported/func_get.svg-093f0ce02889d1f102ff9cc3e7f72654.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=false diff --git a/hexmapper/addons/script-ide/icon/func_set.svg b/hexmapper/addons/script-ide/icon/func_set.svg new file mode 100644 index 0000000..d4613a3 --- /dev/null +++ b/hexmapper/addons/script-ide/icon/func_set.svg @@ -0,0 +1 @@ + diff --git a/hexmapper/addons/script-ide/icon/func_set.svg.import b/hexmapper/addons/script-ide/icon/func_set.svg.import new file mode 100644 index 0000000..8063f5b --- /dev/null +++ b/hexmapper/addons/script-ide/icon/func_set.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bvjkrti6kj6o2" +path="res://.godot/imported/func_set.svg-c31168d90866ff1707ad9834754bd2c9.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/script-ide/icon/func_set.svg" +dest_files=["res://.godot/imported/func_set.svg-c31168d90866ff1707ad9834754bd2c9.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=false diff --git a/hexmapper/addons/script-ide/icon/property.svg b/hexmapper/addons/script-ide/icon/property.svg new file mode 100644 index 0000000..144cda9 --- /dev/null +++ b/hexmapper/addons/script-ide/icon/property.svg @@ -0,0 +1 @@ + diff --git a/hexmapper/addons/script-ide/icon/property.svg.import b/hexmapper/addons/script-ide/icon/property.svg.import new file mode 100644 index 0000000..c9156a5 --- /dev/null +++ b/hexmapper/addons/script-ide/icon/property.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dbwlgnwv5e8kl" +path="res://.godot/imported/property.svg-9e228499f30651faad74aa99e4499d7e.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/script-ide/icon/property.svg" +dest_files=["res://.godot/imported/property.svg-9e228499f30651faad74aa99e4499d7e.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=false diff --git a/hexmapper/addons/script-ide/icon/signal.svg b/hexmapper/addons/script-ide/icon/signal.svg new file mode 100644 index 0000000..d3f97b8 --- /dev/null +++ b/hexmapper/addons/script-ide/icon/signal.svg @@ -0,0 +1 @@ + diff --git a/hexmapper/addons/script-ide/icon/signal.svg.import b/hexmapper/addons/script-ide/icon/signal.svg.import new file mode 100644 index 0000000..4c029b0 --- /dev/null +++ b/hexmapper/addons/script-ide/icon/signal.svg.import @@ -0,0 +1,38 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bnccvnaloqnte" +path="res://.godot/imported/signal.svg-97182e1498b520a1ff5b8b9017c3b480.ctex" +metadata={ +"has_editor_variant": true, +"vram_texture": false +} + +[deps] + +source_file="res://addons/script-ide/icon/signal.svg" +dest_files=["res://.godot/imported/signal.svg-97182e1498b520a1ff5b8b9017c3b480.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=false diff --git a/hexmapper/addons/script-ide/override/override_panel.gd b/hexmapper/addons/script-ide/override/override_panel.gd new file mode 100644 index 0000000..aa3007d --- /dev/null +++ b/hexmapper/addons/script-ide/override/override_panel.gd @@ -0,0 +1,220 @@ +@tool +extends PopupPanel + +const FUNC_META: StringName = &"func" + +@onready var filter_txt: LineEdit = %FilterTxt +@onready var class_func_tree: Tree = %ClassFuncTree +@onready var ok_btn: Button = %OkBtn +@onready var cancel_btn: Button = %CancelBtn + +var plugin: EditorPlugin + +var selections: int = 0 +var class_to_functions: Dictionary[StringName, PackedStringArray] + +func _ready() -> void: + filter_txt.text_changed.connect(update_tree_filter.unbind(1)) + + class_func_tree.multi_selected.connect(func(item: TreeItem, col: int, selected: bool): count_selection(selected)) + class_func_tree.item_activated.connect(generate_functions) + + cancel_btn.pressed.connect(hide) + ok_btn.pressed.connect(generate_functions) + + about_to_popup.connect(on_show) + +func update_tree_filter(): + update_tree() + +func count_selection(selected: bool): + if (selected): + selections += 1 + else: + selections -= 1 + + ok_btn.disabled = selections == 0 + +func on_show(): + class_func_tree.clear() + selections = 0 + ok_btn.disabled = true + filter_txt.text = &"" + + var script: Script = EditorInterface.get_script_editor().get_current_script() + class_to_functions = collect_all_class_functions(script) # [StringName, PackedStringArray] + if (class_to_functions.is_empty()): + return + + update_tree() + filter_txt.grab_focus() + +func update_tree(): + class_func_tree.clear() + + var text: String = filter_txt.text + + var root: TreeItem = class_func_tree.create_item() + for class_name_str: StringName in class_to_functions.keys(): + var class_item: TreeItem = root.create_child(0) + class_item.set_selectable(0, false) + class_item.set_text(0, class_name_str) + + for function: String in class_to_functions.get(class_name_str): + if (text.is_empty() || text.is_subsequence_ofn(function)): + var func_item: TreeItem = class_item.create_child() + func_item.set_text(0, function) + if (plugin.keywords.has(function.get_slice("(", 0))): + func_item.set_icon(0, plugin.engine_func_icon) + else: + func_item.set_icon(0, plugin.func_icon) + func_item.set_meta(FUNC_META, function) + +func collect_all_class_functions(script: Script) -> Dictionary[StringName, PackedStringArray]: + var existing_funcs: Dictionary[String, int] = {} # Used as Set. + for func_str: String in plugin.outline_cache.engine_funcs: + existing_funcs[func_str] = 0 + for func_str: String in plugin.outline_cache.funcs: + existing_funcs[func_str] = 0 + + var class_to_functions: Dictionary[StringName, PackedStringArray] = collect_super_class_functions(script.get_base_script(), existing_funcs) + var native_class_to_functions: Dictionary[StringName, PackedStringArray] = collect_native_class_functions(script.get_instance_base_type(), existing_funcs) + + return native_class_to_functions.merged(class_to_functions) + +func collect_super_class_functions(base_script: Script, existing_funcs: Dictionary[String, int]) -> Dictionary[StringName, PackedStringArray]: + var super_classes: Array[Script] = [] + while (base_script != null): + super_classes.insert(0, base_script) + + base_script = base_script.get_base_script() + + var class_to_functions: Dictionary[StringName, PackedStringArray] = {} + for super_class: Script in super_classes: + var functions: PackedStringArray = collect_script_functions(super_class, existing_funcs) + if (functions.is_empty()): + continue + + class_to_functions[super_class.get_global_name()] = functions + + return class_to_functions + +func collect_native_class_functions(native_class: StringName, existing_funcs: Dictionary[String, int]) -> Dictionary[StringName, PackedStringArray]: + var super_native_classes: Array[StringName] = [] + while (native_class != &""): + super_native_classes.insert(0, native_class) + + native_class = ClassDB.get_parent_class(native_class) + + var class_to_functions: Dictionary[StringName, PackedStringArray] = {} + for super_native_class: StringName in super_native_classes: + var functions: PackedStringArray = collect_class_functions(super_native_class, existing_funcs) + if (functions.is_empty()): + continue + + class_to_functions[super_native_class] = functions + + return class_to_functions + +func collect_class_functions(native_class: StringName, existing_funcs: Dictionary[String, int]): + var functions: PackedStringArray = [] + + for method: Dictionary in ClassDB.class_get_method_list(native_class, true): + if (method[&"flags"] & METHOD_FLAG_VIRTUAL <= 0): + continue + + var func_name: String = method[&"name"] + if (existing_funcs.has(func_name)): + continue + + func_name = create_function_signature(method) + functions.append(func_name) + + return functions + +func collect_script_functions(super_class: Script, existing_funcs: Dictionary[String, int]) -> PackedStringArray: + var functions: PackedStringArray = [] + + for method: Dictionary in super_class.get_script_method_list(): + var func_name: String = method[&"name"] + if (existing_funcs.has(func_name)): + continue + + existing_funcs[func_name] = 0 + + func_name = create_function_signature(method) + functions.append(func_name) + + return functions + +func create_function_signature(method: Dictionary) -> String: + var func_name: String = method[&"name"] + func_name += "(" + + var arg_str: String = "" + for arg: Dictionary in method[&"args"]: + if (arg_str != ""): + arg_str += ", " + + arg_str += arg[&"name"] + var type: String = get_type(arg) + if (type != ""): + arg_str += ": " + type + + func_name += arg_str + ")" + + var return_str: String = get_type(method[&"return"]) + if (return_str != ""): + func_name += " -> " + return_str + + return func_name + +func generate_functions(): + var selected_item: TreeItem = class_func_tree.get_next_selected(null) + if (selected_item == null): + return + + var selected_functions: PackedStringArray = [] + + while (selected_item != null): + var function: String = selected_item.get_meta(FUNC_META) + selected_functions.append(function) + + selected_item = class_func_tree.get_next_selected(selected_item) + + var generated_text: String = "" + for function: String in selected_functions: + generated_text += "\nfunc " + function + ":\n\tpass\n" + + var editor: CodeEdit = EditorInterface.get_script_editor().get_current_editor().get_base_editor() + editor.text += generated_text + + plugin.goto_line(editor.get_line_count() - 1) + + hide() + +func get_type(dict: Dictionary) -> String: + var type: String = dict[&"class_name"] + if (type != &""): + return type + + var type_hint: int = dict[&"type"] + if (type_hint == 0): + return &"" + + type = type_string(type_hint) + # Dictionary + if (type_hint == 27): + var generic: String = dict[&"hint_string"] + if (generic != &""): + var generic_parts: PackedStringArray = generic.split(";") + if (generic_parts.size() == 2): + return type + "[" + generic_parts[0] + ", " + generic_parts[1] + "]" + + # Array + if (type_hint == 28): + var generic: String = dict[&"hint_string"] + if (generic != &""): + return type + "[" + generic + "]" + + return type diff --git a/hexmapper/addons/script-ide/override/override_panel.gd.uid b/hexmapper/addons/script-ide/override/override_panel.gd.uid new file mode 100644 index 0000000..131d404 --- /dev/null +++ b/hexmapper/addons/script-ide/override/override_panel.gd.uid @@ -0,0 +1 @@ +uid://caxvtvop03tpo diff --git a/hexmapper/addons/script-ide/override/override_panel.tscn b/hexmapper/addons/script-ide/override/override_panel.tscn new file mode 100644 index 0000000..7a1f72a --- /dev/null +++ b/hexmapper/addons/script-ide/override/override_panel.tscn @@ -0,0 +1,59 @@ +[gd_scene load_steps=2 format=3 uid="uid://bb1n82qxlqanh"] + +[ext_resource type="Script" uid="uid://jwla7ovpvhdw" path="res://addons/script-ide/override/override_panel.gd" id="1_c3eqr"] + +[node name="OverridePanel" type="PopupPanel"] +size = Vector2i(551, 194) +visible = true +script = ExtResource("1_c3eqr") + +[node name="PanelContainer" type="PanelContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 9.0 +offset_top = 9.0 +offset_right = -9.0 +offset_bottom = -9.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="MarginContainer" type="MarginContainer" parent="PanelContainer"] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"] +layout_mode = 2 +theme_override_constants/separation = 4 + +[node name="Label" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Select Functions to Override/Implement" + +[node name="FilterTxt" type="LineEdit" parent="PanelContainer/MarginContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +placeholder_text = "Filter Methods" + +[node name="ClassFuncTree" type="Tree" parent="PanelContainer/MarginContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 +hide_root = true +select_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 4 +alignment = 2 + +[node name="OkBtn" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(64, 0) +layout_mode = 2 +text = "Ok" + +[node name="CancelBtn" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(64, 0) +layout_mode = 2 +text = "Cancel" diff --git a/hexmapper/addons/script-ide/plugin.cfg b/hexmapper/addons/script-ide/plugin.cfg new file mode 100644 index 0000000..21995de --- /dev/null +++ b/hexmapper/addons/script-ide/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Script-IDE" +description="Transforms the Script UI into an IDE like UI. Tabs are used for navigating between scripts. The default Outline got an overhaul and now shows all members of the script (not just methods) with unique icons for faster navigation. Enhanced keyboard navigation for Scripts and Outline. Fast quick search functionality." +author="Marius Hanl" +version="1.9.0" +script="plugin.gd" diff --git a/hexmapper/addons/script-ide/plugin.gd b/hexmapper/addons/script-ide/plugin.gd new file mode 100644 index 0000000..999459e --- /dev/null +++ b/hexmapper/addons/script-ide/plugin.gd @@ -0,0 +1,1338 @@ +## Copyright (c) 2023-present Marius Hanl under the MIT License. +## The editor plugin entrypoint for Script-IDE. +## +## The Script Tabs and Outline modifies the code that is inside 'script_editor_plugin.cpp'. +## That is, the structure is changed a little bit. +## The internals of then native C++ code are therefore important in order to make this plugin work +## without interfering with the Engine. +## All the other functionality does not modify anything Engine related. +## +## Script-IDE does not use global class_name's in order to not clutter projects using it. +## Especially since this is an editor only plugin, we do not want this plugin in the final game. +## Therefore, code that references other code inside this plugin is untyped. +@tool +extends EditorPlugin + +const GETTER: StringName = &"get" +const SETTER: StringName = &"set" +const UNDERSCORE: StringName = &"_" +const INLINE: StringName = &"@" + +const BUILT_IN_SCRIPT: StringName = &"::GDScript" + +#region Settings and Shortcuts +## Editor setting path +const SCRIPT_IDE: StringName = &"plugin/script_ide/" +## Editor setting for the outline position +const OUTLINE_POSITION_RIGHT: StringName = SCRIPT_IDE + &"outline_position_right" +## Editor setting to control the order of the outline +const OUTLINE_ORDER: StringName = SCRIPT_IDE + &"outline_order" +## Editor setting to control whether private members (annotated with '_' should be hidden or not) +const HIDE_PRIVATE_MEMBERS: StringName = SCRIPT_IDE + &"hide_private_members" +## Editor setting to control whether we want to auto navigate to the script +## in the filesystem (dock) when selected +const AUTO_NAVIGATE_IN_FS: StringName = SCRIPT_IDE + &"auto_navigate_in_filesystem_dock" +## Editor setting to control whether the script list should be visible or not +const SCRIPT_LIST_VISIBLE: StringName = SCRIPT_IDE + &"script_list_visible" +## Editor setting to control whether the script tabs should be visible or not. +const SCRIPT_TABS_VISIBLE: StringName = SCRIPT_IDE + &"script_tabs_visible" +## Editor setting to control where the script tabs should be. +const SCRIPT_TAB_POSITION_TOP: StringName = SCRIPT_IDE + &"script_tab_position_top" + +## Editor setting for the 'Open Outline Popup' shortcut +const OPEN_OUTLINE_POPUP: StringName = SCRIPT_IDE + &"open_outline_popup" +## Editor setting for the 'Open Scripts Popup' shortcut +const OPEN_SCRIPTS_POPUP: StringName = SCRIPT_IDE + &"open_scripts_popup" +## Editor setting for the 'Open Scripts Popup' shortcut +const OPEN_QUICK_SEARCH_POPUP: StringName = SCRIPT_IDE + &"open_quick_search_popup" +## Editor setting for the 'Open Override Popup' shortcut +const OPEN_OVERRIDE_POPUP: StringName = SCRIPT_IDE + &"open_override_popup" +## Editor setting for the 'Tab cycle forward' shortcut +const TAB_CYCLE_FORWARD: StringName = SCRIPT_IDE + &"tab_cycle_forward" +## Editor setting for the 'Tab cycle backward' shortcut +const TAB_CYCLE_BACKWARD: StringName = SCRIPT_IDE + &"tab_cycle_backward" +#endregion + +#region Outline type name and icon +const ENGINE_FUNCS: StringName = &"Engine Callbacks" +const FUNCS: StringName = &"Functions" +const SIGNALS: StringName = &"Signals" +const EXPORTED: StringName = &"Exported Properties" +const PROPERTIES: StringName = &"Properties" +const CLASSES: StringName = &"Classes" +const CONSTANTS: StringName = &"Constants" + +var engine_func_icon: Texture2D +var func_icon: Texture2D +var func_get_icon: Texture2D +var func_set_icon: Texture2D +var property_icon: Texture2D +var export_icon: Texture2D +var signal_icon: Texture2D +var constant_icon: Texture2D +var class_icon: Texture2D +#endregion + +#region Editor settings +var is_outline_right: bool = true +var is_script_list_visible: bool = false +var hide_private_members: bool = false +var is_auto_navigate_in_fs: bool = true +var is_script_tabs_visible: bool = true +var is_script_tabs_top: bool = true +var outline_order: PackedStringArray + +var open_outline_popup_shc: Shortcut +var open_scripts_popup_shc: Shortcut +var open_quick_search_popup_shc: Shortcut +var open_override_popup_shc: Shortcut +var tab_cycle_forward_shc: Shortcut +var tab_cycle_backward_shc: Shortcut +#endregion + +#region Existing controls we modify +var outline_container: Control +var outline_parent: Control +var scripts_tab_container: TabContainer +var scripts_tab_bar: TabBar +var script_filter_txt: LineEdit +var scripts_item_list: ItemList +var panel_container: VSplitContainer + +var split_container: HSplitContainer +var old_outline: ItemList +var outline_filter_txt: LineEdit +var sort_btn: Button +#endregion + +#region Own controls we add +var outline: ItemList +var outline_popup: PopupPanel +var filter_box: HBoxContainer + +var scripts_popup: PopupPanel +var quick_open_popup: PopupPanel +var override_popup: PopupPanel + +var class_btn: Button +var constant_btn: Button +var signal_btn: Button +var property_btn: Button +var export_btn: Button +var func_btn: Button +var engine_func_btn: Button +#endregion + +#region Plugin variables +var keywords: Dictionary[String, int] = {} # Used as Set. +var outline_type_order: Array[OutlineType] = [] +var outline_cache: OutlineCache +var tab_state: TabStateCache + +var old_script_editor_base: ScriptEditorBase +var old_script_type: StringName + +var selected_tab: int = -1 +var last_tab_hovered: int = -1 +var sync_script_list: bool = false +var file_to_navigate: String = &"" +var suppress_settings_sync: bool = false + +const QUICK_OPEN_INTERVAL: int = 400 +var quick_open_tween: Tween +#endregion + +#region Plugin Enter / Exit setup +## Change the Godot script UI and transform into an IDE like UI +func _enter_tree() -> void: + init_icons() + init_settings() + init_shortcuts() + + # Update on filesystem changed (e.g. save operation). + var file_system: EditorFileSystem = EditorInterface.get_resource_filesystem() + file_system.filesystem_changed.connect(schedule_update) + + # Sync settings changes for this plugin. + get_editor_settings().settings_changed.connect(sync_settings) + + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + + # Change script item list visibility (based on settings). + scripts_item_list = find_or_null(script_editor.find_children("*", "ItemList", true, false)) + scripts_item_list.allow_reselect = true + scripts_item_list.item_selected.connect(hide_scripts_popup.unbind(1)) + update_script_list_visibility() + + # Add script filter navigation. + script_filter_txt = find_or_null(scripts_item_list.get_parent().find_children("*", "LineEdit", true, false)) + script_filter_txt.gui_input.connect(navigate_on_list.bind(scripts_item_list, select_script)) + + # Make tab container visible. + scripts_tab_container = find_or_null(script_editor.find_children("*", "TabContainer", true, false)) + scripts_tab_bar = scripts_tab_container.get_tab_bar() + + # Save old tab state to restore later. + tab_state = TabStateCache.new() + tab_state.save(scripts_tab_container, scripts_tab_bar) + + # Create and set script popup. + create_set_scripts_popup() + + # Configure tab container and bar. + scripts_tab_container.tabs_visible = is_script_tabs_visible + scripts_tab_container.drag_to_rearrange_enabled = true + scripts_tab_container.auto_translate_mode = Node.AUTO_TRANSLATE_MODE_DISABLED + update_tabs_position() + + scripts_tab_bar.tab_close_display_policy = TabBar.CLOSE_BUTTON_SHOW_ACTIVE_ONLY + scripts_tab_bar.drag_to_rearrange_enabled = true + scripts_tab_bar.select_with_rmb = true + scripts_tab_bar.tab_close_pressed.connect(on_tab_close) + scripts_tab_bar.tab_rmb_clicked.connect(on_tab_rmb) + scripts_tab_bar.tab_hovered.connect(on_tab_hovered) + scripts_tab_bar.mouse_exited.connect(on_tab_bar_mouse_exited) + scripts_tab_bar.active_tab_rearranged.connect(on_active_tab_rearranged) + scripts_tab_bar.gui_input.connect(on_tab_bar_gui_input) + + scripts_tab_bar.tab_changed.connect(on_tab_changed) + + # Remove existing outline and add own outline. + split_container = find_or_null(script_editor.find_children("*", "HSplitContainer", true, false)) + outline_container = split_container.get_child(0) + + if (is_outline_right): + update_outline_position() + + old_outline = find_or_null(outline_container.find_children("*", "ItemList", true, false), 1) + outline_parent = old_outline.get_parent() + outline_parent.remove_child(old_outline) + + outline = ItemList.new() + outline.allow_reselect = true + outline.size_flags_vertical = Control.SIZE_EXPAND_FILL + outline_parent.add_child(outline) + + outline.item_selected.connect(scroll_outline) + + # Add a filter box for all kind of members + filter_box = HBoxContainer.new() + + engine_func_btn = create_filter_btn(engine_func_icon, ENGINE_FUNCS) + func_btn = create_filter_btn(func_icon, FUNCS) + signal_btn = create_filter_btn(signal_icon, SIGNALS) + export_btn = create_filter_btn(export_icon, EXPORTED) + property_btn = create_filter_btn(property_icon, PROPERTIES) + class_btn = create_filter_btn(class_icon, CLASSES) + constant_btn = create_filter_btn(constant_icon, CONSTANTS) + update_outline_button_order() + + outline.get_parent().add_child(filter_box) + outline.get_parent().move_child(filter_box, outline.get_index()) + + # Add navigation to the filter and text filtering. + outline_filter_txt = find_or_null(outline_container.find_children("*", "LineEdit", true, false), 1) + outline_filter_txt.gui_input.connect(navigate_on_list.bind(outline, scroll_outline)) + outline_filter_txt.text_changed.connect(update_outline.unbind(1)) + + # Add callback when the sorting changed. + sort_btn = find_or_null(outline_container.find_children("*", "Button", true, false)) + sort_btn.pressed.connect(update_outline) + + on_tab_changed(scripts_tab_bar.current_tab) + +## Restore the old Godot script UI and free everything we created +func _exit_tree() -> void: + var file_system: EditorFileSystem = EditorInterface.get_resource_filesystem() + file_system.filesystem_changed.disconnect(schedule_update) + + if (old_script_editor_base != null): + old_script_editor_base.edited_script_changed.disconnect(update_selected_tab) + + if (split_container != null): + if (split_container != outline_container.get_parent()): + split_container.add_child(outline_container) + + # Try to restore the previous split offset. + if (is_outline_right): + var split_offset: float = split_container.get_child(1).size.x + split_container.split_offset = split_offset + + split_container.move_child(outline_container, 0) + + outline_filter_txt.gui_input.disconnect(navigate_on_list) + outline_filter_txt.text_changed.disconnect(update_outline) + sort_btn.pressed.disconnect(update_outline) + + outline.item_selected.disconnect(scroll_outline) + + outline_parent.remove_child(filter_box) + outline_parent.remove_child(outline) + outline_parent.add_child(old_outline) + outline_parent.move_child(old_outline, 2) + + filter_box.free() + outline.free() + + if (scripts_tab_container != null): + tab_state.restore(scripts_tab_container, scripts_tab_bar) + + scripts_tab_container.pre_popup_pressed.disconnect(prepare_scripts_popup) + scripts_tab_container.set_popup(null) + scripts_popup.free() + + if (scripts_tab_bar != null): + scripts_tab_bar.mouse_exited.disconnect(on_tab_bar_mouse_exited) + scripts_tab_bar.gui_input.disconnect(on_tab_bar_gui_input) + scripts_tab_bar.tab_close_pressed.disconnect(on_tab_close) + scripts_tab_bar.tab_rmb_clicked.disconnect(on_tab_rmb) + scripts_tab_bar.tab_hovered.disconnect(on_tab_hovered) + scripts_tab_bar.active_tab_rearranged.disconnect(on_active_tab_rearranged) + + scripts_tab_bar.tab_changed.disconnect(on_tab_changed) + + if (scripts_item_list != null): + scripts_item_list.allow_reselect = false + scripts_item_list.item_selected.disconnect(hide_scripts_popup) + scripts_item_list.get_parent().visible = true + + if (script_filter_txt != null): + script_filter_txt.gui_input.disconnect(navigate_on_list) + + if (outline_popup != null): + outline_popup.free() + if (quick_open_popup != null): + quick_open_popup.free() + if (override_popup != null): + override_popup.free() + + get_editor_settings().settings_changed.disconnect(sync_settings) +#endregion + +#region Plugin and Shortcut processing +## Lazy pattern to update the editor only once per frame +func _process(delta: float) -> void: + update_editor() + set_process(false) + +## Process the user defined shortcuts +func _shortcut_input(event: InputEvent) -> void: + if (!event.is_pressed() || event.is_echo()): + return + + if (open_outline_popup_shc.matches_event(event)): + get_viewport().set_input_as_handled() + open_outline_popup() + elif (open_scripts_popup_shc.matches_event(event)): + get_viewport().set_input_as_handled() + open_scripts_popup() + elif (open_quick_search_popup_shc.matches_event(event)): + if (quick_open_tween != null && quick_open_tween.is_running()): + get_viewport().set_input_as_handled() + if (quick_open_tween != null): + quick_open_tween.kill() + + quick_open_tween = create_tween() + quick_open_tween.tween_interval(0.1) + quick_open_tween.tween_callback(open_quick_search_popup) + quick_open_tween.tween_callback(func(): quick_open_tween = null) + else: + quick_open_tween = create_tween() + quick_open_tween.tween_interval(QUICK_OPEN_INTERVAL / 1000.0) + quick_open_tween.tween_callback(func(): quick_open_tween = null) + elif (open_override_popup_shc.matches_event(event)): + get_viewport().set_input_as_handled() + open_override_popup() + elif (EditorInterface.get_script_editor().is_visible_in_tree()): + if (tab_cycle_forward_shc.matches_event(event)): + get_viewport().set_input_as_handled() + + var new_tab: int = scripts_tab_container.current_tab + 1 + if (new_tab == scripts_tab_container.get_tab_count()): + new_tab = 0 + scripts_tab_container.current_tab = new_tab + elif (tab_cycle_backward_shc.matches_event(event)): + get_viewport().set_input_as_handled() + + var new_tab: int = scripts_tab_container.current_tab - 1 + if (new_tab == -1): + new_tab = scripts_tab_container.get_tab_count() - 1 + scripts_tab_container.current_tab = new_tab + +## May cancels the quick search shortcut timer. +func _input(event: InputEvent) -> void: + if (event is InputEventKey): + if (!open_quick_search_popup_shc.matches_event(event)): + if (quick_open_tween != null): + quick_open_tween.kill() + quick_open_tween = null +#endregion + +#region Icon, Settings, Shortcut initialization +## Initializes all plugin icons, while respecting the editor settings. +func init_icons(): + engine_func_icon = create_editor_texture(load_rel("icon/engine_func.svg")) + func_icon = create_editor_texture(load_rel("icon/func.svg")) + func_get_icon = create_editor_texture(load_rel("icon/func_get.svg")) + func_set_icon = create_editor_texture(load_rel("icon/func_set.svg")) + property_icon = create_editor_texture(load_rel("icon/property.svg")) + export_icon = create_editor_texture(load_rel("icon/export.svg")) + signal_icon = create_editor_texture(load_rel("icon/signal.svg")) + constant_icon = create_editor_texture(load_rel("icon/constant.svg")) + class_icon = create_editor_texture(load_rel("icon/class.svg")) + +## Initializes all settings. +## Every setting can be changed while this plugin is active, which will override them. +func init_settings(): + is_outline_right = get_setting(OUTLINE_POSITION_RIGHT, is_outline_right) + hide_private_members = get_setting(HIDE_PRIVATE_MEMBERS, hide_private_members) + is_script_list_visible = get_setting(SCRIPT_LIST_VISIBLE, is_script_list_visible) + is_auto_navigate_in_fs = get_setting(AUTO_NAVIGATE_IN_FS, is_auto_navigate_in_fs) + is_script_tabs_visible = get_setting(SCRIPT_TABS_VISIBLE, is_script_tabs_visible) + is_script_tabs_top = get_setting(SCRIPT_TAB_POSITION_TOP, is_script_tabs_top) + + init_outline_order() + +## Initializes the outline type structure and sorts it based off the outline order. +func init_outline_order(): + var outline_type: OutlineType = OutlineType.new() + outline_type.type_name = ENGINE_FUNCS + outline_type.add_to_outline = func(): add_to_outline_if_selected(engine_func_btn, + func(): add_to_outline(outline_cache.engine_funcs, engine_func_icon, &"func")) + outline_type_order.append(outline_type) + + outline_type = OutlineType.new() + outline_type.type_name = FUNCS + outline_type.add_to_outline = func(): add_to_outline_if_selected(func_btn, + func(): add_to_outline_ext(outline_cache.funcs, get_func_icon, &"func", &"static")) + outline_type_order.append(outline_type) + + outline_type = OutlineType.new() + outline_type.type_name = SIGNALS + outline_type.add_to_outline = func(): add_to_outline_if_selected(signal_btn, + func(): add_to_outline(outline_cache.signals, signal_icon, &"signal")) + outline_type_order.append(outline_type) + + outline_type = OutlineType.new() + outline_type.type_name = EXPORTED + outline_type.add_to_outline = func(): add_to_outline_if_selected(export_btn, + func(): add_to_outline(outline_cache.exports, export_icon, &"var", &"@export")) + outline_type_order.append(outline_type) + + outline_type = OutlineType.new() + outline_type.type_name = PROPERTIES + outline_type.add_to_outline = func(): add_to_outline_if_selected(property_btn, + func(): add_to_outline(outline_cache.properties, property_icon, &"var")) + outline_type_order.append(outline_type) + + outline_type = OutlineType.new() + outline_type.type_name = CLASSES + outline_type.add_to_outline = func(): add_to_outline_if_selected(class_btn, + func(): add_to_outline(outline_cache.classes, class_icon, &"class")) + outline_type_order.append(outline_type) + + outline_type = OutlineType.new() + outline_type.type_name = CONSTANTS + outline_type.add_to_outline = func(): add_to_outline_if_selected(constant_btn, + func(): add_to_outline(outline_cache.constants, constant_icon, &"const", &"enum")) + outline_type_order.append(outline_type) + + update_outline_order() + +func update_outline_button_order(): + var all_buttons: Array[Button] = [engine_func_btn, func_btn, signal_btn, export_btn, property_btn, class_btn, constant_btn] + all_buttons.sort_custom(sort_buttons_by_outline_order) + + for btn: Button in all_buttons: + if (btn.get_parent() != null): + filter_box.remove_child(btn) + + for btn: Button in all_buttons: + filter_box.add_child(btn) + +func update_outline_order(): + var editor_settings: EditorSettings = get_editor_settings() + if (editor_settings.has_setting(OUTLINE_ORDER)): + outline_order = editor_settings.get_setting(OUTLINE_ORDER) + else: + outline_order = [ENGINE_FUNCS, FUNCS, SIGNALS, EXPORTED, PROPERTIES, CONSTANTS, CLASSES] + editor_settings.set_setting(OUTLINE_ORDER, outline_order) + + outline_type_order.sort_custom(sort_types_by_outline_order) + +func sort_buttons_by_outline_order(btn1: Button, btn2: Button) -> bool: + return sort_by_outline_order(btn1.tooltip_text, btn2.tooltip_text) + +func sort_types_by_outline_order(type1: OutlineType, type2: OutlineType) -> bool: + return sort_by_outline_order(type1.type_name, type2.type_name) + +func sort_by_outline_order(outline_type1: StringName, outline_type2: StringName) -> bool: + return outline_order.find(outline_type1) < outline_order.find(outline_type2) + +## Initializes all shortcuts. +## Every shortcut can be changed while this plugin is active, which will override them. +func init_shortcuts(): + var editor_settings: EditorSettings = get_editor_settings() + if (!editor_settings.has_setting(OPEN_OUTLINE_POPUP)): + var shortcut: Shortcut = Shortcut.new() + var event: InputEventKey = InputEventKey.new() + event.device = -1 + event.command_or_control_autoremap = true + event.keycode = KEY_O + + shortcut.events = [ event ] + editor_settings.set_setting(OPEN_OUTLINE_POPUP, shortcut) + + if (!editor_settings.has_setting(OPEN_SCRIPTS_POPUP)): + var shortcut: Shortcut = Shortcut.new() + var event: InputEventKey = InputEventKey.new() + event.device = -1 + event.command_or_control_autoremap = true + event.keycode = KEY_U + + shortcut.events = [ event ] + editor_settings.set_setting(OPEN_SCRIPTS_POPUP, shortcut) + + if (!editor_settings.has_setting(OPEN_QUICK_SEARCH_POPUP)): + var shortcut: Shortcut = Shortcut.new() + var event: InputEventKey = InputEventKey.new() + event.device = -1 + event.keycode = KEY_SHIFT + + shortcut.events = [ event ] + editor_settings.set_setting(OPEN_QUICK_SEARCH_POPUP, shortcut) + + if (!editor_settings.has_setting(OPEN_OVERRIDE_POPUP)): + var shortcut: Shortcut = Shortcut.new() + var event: InputEventKey = InputEventKey.new() + event.device = -1 + event.keycode = KEY_INSERT + event.alt_pressed = true + + shortcut.events = [ event ] + editor_settings.set_setting(OPEN_OVERRIDE_POPUP, shortcut) + + if (!editor_settings.has_setting(TAB_CYCLE_FORWARD)): + var shortcut: Shortcut = Shortcut.new() + var event: InputEventKey = InputEventKey.new() + event.device = -1 + event.keycode = KEY_TAB + event.ctrl_pressed = true + + shortcut.events = [ event ] + editor_settings.set_setting(TAB_CYCLE_FORWARD, shortcut) + + if (!editor_settings.has_setting(TAB_CYCLE_BACKWARD)): + var shortcut: Shortcut = Shortcut.new() + var event: InputEventKey = InputEventKey.new() + event.device = -1 + event.keycode = KEY_TAB + event.shift_pressed = true + event.ctrl_pressed = true + + shortcut.events = [ event ] + editor_settings.set_setting(TAB_CYCLE_BACKWARD, shortcut) + + open_outline_popup_shc = editor_settings.get_setting(OPEN_OUTLINE_POPUP) + open_scripts_popup_shc = editor_settings.get_setting(OPEN_SCRIPTS_POPUP) + open_quick_search_popup_shc = editor_settings.get_setting(OPEN_QUICK_SEARCH_POPUP) + open_override_popup_shc = editor_settings.get_setting(OPEN_OVERRIDE_POPUP) + tab_cycle_forward_shc = editor_settings.get_setting(TAB_CYCLE_FORWARD) + tab_cycle_backward_shc = editor_settings.get_setting(TAB_CYCLE_BACKWARD) +#endregion + +## Schedules an update on the next frame +func schedule_update(): + set_process(true) + +## Updates all parts of the editor that are needed to be synchronized with the file system change. +func update_editor(): + update_script_text_filter() + + if (sync_script_list): + if (file_to_navigate != &""): + EditorInterface.get_file_system_dock().navigate_to_path(file_to_navigate) + EditorInterface.get_script_editor().get_current_editor().get_base_editor().grab_focus() + file_to_navigate = &"" + + sync_tab_with_script_list() + sync_script_list = false + + update_tabs() + update_outline_cache() + update_outline() + +func add_to_outline_if_selected(btn: Button, action: Callable): + if (btn.button_pressed): + action.call() + +func open_quick_search_popup(): + if (quick_open_popup == null): + quick_open_popup = load_rel("quickopen/quick_open_panel.tscn").instantiate() + quick_open_popup.plugin = self + + if (quick_open_popup.get_parent() != null): + quick_open_popup.get_parent().remove_child(quick_open_popup) + quick_open_popup.popup_exclusive_on_parent(EditorInterface.get_script_editor(), get_center_editor_rect()) + +func open_override_popup(): + var script: Script = get_current_script() + if (!script): + return + + if (override_popup == null): + override_popup = load_rel("override/override_panel.tscn").instantiate() + override_popup.plugin = self + + if (override_popup.get_parent() != null): + override_popup.get_parent().remove_child(override_popup) + override_popup.popup_exclusive_on_parent(EditorInterface.get_script_editor(), get_center_editor_rect()) + +func hide_scripts_popup(): + if (scripts_popup != null && scripts_popup.visible): + scripts_popup.hide.call_deferred() + +func create_set_scripts_popup(): + panel_container = scripts_item_list.get_parent().get_parent() + + scripts_popup = PopupPanel.new() + scripts_popup.popup_hide.connect(restore_scripts_list) + + # Need to be inside the tree, so it can be shown as popup for the tab container. + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + script_editor.add_child(scripts_popup) + + scripts_tab_container.pre_popup_pressed.connect(prepare_scripts_popup) + scripts_tab_container.set_popup(scripts_popup) + +func prepare_scripts_popup(): + scripts_popup.size.x = outline.size.x + scripts_popup.size.y = panel_container.size.y - scripts_tab_bar.size.y + + scripts_item_list.get_parent().reparent(scripts_popup) + scripts_item_list.get_parent().visible = true + + script_filter_txt.grab_focus() + +func restore_scripts_list(): + script_filter_txt.text = &"" + + update_script_list_visibility() + + scripts_item_list.get_parent().reparent(panel_container) + panel_container.move_child(scripts_item_list.get_parent(), 0) + +func navigate_on_list(event: InputEvent, list: ItemList, submit: Callable): + if (event.is_action_pressed(&"ui_text_submit")): + var index: int = get_list_index(list) + if (index == -1): + return + + submit.call(index) + elif (event.is_action_pressed(&"ui_down", true)): + var index: int = get_list_index(list) + if (index == list.item_count - 1): + return + + navigate_list(list, index, 1) + elif (event.is_action_pressed(&"ui_up", true)): + var index: int = get_list_index(list) + if (index <= 0): + return + + navigate_list(list, index, -1) + elif (event.is_action_pressed(&"ui_page_down", true)): + var index: int = get_list_index(list) + if (index == list.item_count - 1): + return + + navigate_list(list, index, 5) + elif (event.is_action_pressed(&"ui_page_up", true)): + var index: int = get_list_index(list) + if (index <= 0): + return + + navigate_list(list, index, -5) + elif (event is InputEventKey && list.item_count > 0 && !list.is_anything_selected()): + list.select(0) + +func get_list_index(list: ItemList) -> int: + var items: PackedInt32Array = list.get_selected_items() + + if (items.is_empty()): + return -1 + + return items[0] + +func navigate_list(list: ItemList, index: int, amount: int): + index = clamp(index + amount, 0, list.item_count - 1) + + list.select(index) + list.ensure_current_is_visible() + list.accept_event() + +func get_center_editor_rect() -> Rect2i: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + + var size: Vector2i = Vector2i(400, 500) + var x: int + var y: int + + if (script_editor.get_parent().get_parent() is Window): + # Floating editor. + var window: Window = script_editor.get_parent().get_parent() + var window_rect: Rect2 = window.get_visible_rect() + + x = window_rect.size.x / 2 - size.x / 2 + y = window_rect.size.y / 2 - size.y / 2 + else: + x = script_editor.global_position.x + script_editor.size.x / 2 - size.x / 2 + y = script_editor.global_position.y + script_editor.size.y / 2 - size.y / 2 + + return Rect2i(Vector2i(x, y), size) + +func open_outline_popup(): + var button_flags: Array[bool] = [] + for child: Node in filter_box.get_children(): + var btn: Button = child + button_flags.append(btn.button_pressed) + + btn.set_pressed_no_signal(true) + + var old_text: String = outline_filter_txt.text + outline_filter_txt.text = &"" + + if (outline_popup == null): + outline_popup = PopupPanel.new() + + var outline_initially_closed: bool = !outline_container.visible + if (outline_initially_closed): + outline_container.visible = true + + outline_container.reparent(outline_popup) + + outline_popup.popup_hide.connect(on_outline_popup_hidden.bind(outline_initially_closed, old_text, button_flags)) + + if (outline_popup.get_parent() != null): + outline_popup.get_parent().remove_child(outline_popup) + outline_popup.popup_exclusive_on_parent(EditorInterface.get_script_editor(), get_center_editor_rect()) + + update_outline() + outline_filter_txt.grab_focus() + +func on_outline_popup_hidden(outline_initially_closed: bool, old_text: String, button_flags: Array[bool]): + outline_popup.popup_hide.disconnect(on_outline_popup_hidden) + + if outline_initially_closed: + outline_container.visible = false + + outline_container.reparent(split_container) + if (!is_outline_right): + split_container.move_child(outline_container, 0) + + outline_filter_txt.text = old_text + + var index: int = 0 + for flag: bool in button_flags: + var btn: Button = filter_box.get_child(index) + btn.set_pressed_no_signal(flag) + index += 1 + + update_outline() + +func open_scripts_popup(): + scripts_item_list.get_parent().reparent(scripts_popup) + scripts_item_list.get_parent().visible = true + + if (scripts_popup.get_parent() != null): + scripts_popup.get_parent().remove_child(scripts_popup) + scripts_popup.popup_exclusive_on_parent(EditorInterface.get_script_editor(), get_center_editor_rect()) + + script_filter_txt.grab_focus() + +## Removes the script filter text and emits the signal so that the tabs stay +## and we do not break anything there. +func update_script_text_filter(): + if (script_filter_txt.text != &""): + script_filter_txt.text = &"" + script_filter_txt.text_changed.emit(&"") + +func get_current_script() -> Script: + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + return script_editor.get_current_script() + +func select_script(selected_idx: int): + hide_scripts_popup() + + scripts_item_list.item_selected.emit(selected_idx) + +func scroll_outline(selected_idx: int): + if (outline_popup != null && outline_popup.visible): + outline_popup.hide.call_deferred() + + var script: Script = get_current_script() + if (!script): + return + + var text: String = outline.get_item_text(selected_idx) + var metadata: Dictionary[StringName, StringName] = outline.get_item_metadata(selected_idx) + var modifier: StringName = metadata[&"modifier"] + var type: StringName = metadata[&"type"] + + var type_with_text: String = type + " " + text + if (type == &"func"): + type_with_text = type_with_text + "(" + + var source_code: String = script.get_source_code() + var lines: PackedStringArray = source_code.split("\n") + + var index: int = 0 + for line: String in lines: + # Easy case, like 'var abc' + if (line.begins_with(type_with_text)): + goto_line(index) + return + + # We have an modifier, e.g. 'static' + if (modifier != &"" && line.begins_with(modifier)): + if (line.begins_with(modifier + " " + type_with_text)): + goto_line(index) + return + # Special case: An 'enum' is treated different. + elif (modifier == &"enum" && line.contains("enum " + text)): + goto_line(index) + return + + # Hard case, probably something like '@onready var abc' + if (type == &"var" && line.contains(type_with_text)): + goto_line(index) + return + + index += 1 + + push_error(type_with_text + " or " + modifier + " not found in source code") + +func goto_line(index: int): + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + script_editor.goto_line(index) + + var code_edit: CodeEdit = script_editor.get_current_editor().get_base_editor() + code_edit.set_caret_line(index) + code_edit.set_v_scroll(index) + code_edit.set_caret_column(code_edit.get_line(index).length()) + code_edit.set_h_scroll(0) + + code_edit.grab_focus() + +func create_filter_btn(icon: Texture2D, title: StringName) -> Button: + var btn: Button = Button.new() + btn.toggle_mode = true + btn.icon = icon + btn.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER + btn.tooltip_text = title + + var property: StringName = SCRIPT_IDE + title.to_lower().replace(" ", "_") + btn.set_meta(&"property", property) + btn.button_pressed = get_setting(property, true) + + btn.toggled.connect(on_filter_button_pressed.bind(btn)) + btn.gui_input.connect(on_right_click.bind(btn)) + + btn.add_theme_color_override(&"icon_pressed_color", Color.WHITE) + btn.add_theme_color_override(&"icon_hover_color", Color.WHITE) + btn.add_theme_color_override(&"icon_hover_pressed_color", Color.WHITE) + btn.add_theme_color_override(&"icon_focus_color", Color.WHITE) + + var style_box_empty: StyleBoxEmpty = StyleBoxEmpty.new() + btn.add_theme_stylebox_override(&"normal", style_box_empty) + + var style_box: StyleBoxFlat = StyleBoxFlat.new() + style_box.draw_center = false + style_box.border_color = get_editor_accent_color() + style_box.set_border_width_all(1 * get_editor_scale()) + style_box.set_corner_radius_all(get_editor_corner_radius() * get_editor_scale()) + btn.add_theme_stylebox_override(&"focus", style_box) + + return btn + +func on_right_click(event: InputEvent, btn: Button): + if !(event is InputEventMouseButton): + return + + var mouse_event: InputEventMouseButton = event + + if (!mouse_event.is_pressed() || mouse_event.button_index != MOUSE_BUTTON_RIGHT): + return + + btn.button_pressed = true + + var pressed_state: bool = false + for child: Node in filter_box.get_children(): + var other_btn: Button = child + + if (btn != other_btn): + pressed_state = pressed_state || other_btn.button_pressed + + for child: Node in filter_box.get_children(): + var other_btn: Button = child + + if (btn != other_btn): + other_btn.button_pressed = !pressed_state + + outline_filter_txt.grab_focus() + +func on_filter_button_pressed(pressed: bool, btn: Button): + set_setting(btn.get_meta(&"property"), pressed) + + update_outline() + outline_filter_txt.grab_focus() + +func update_outline_position(): + if (is_outline_right): + # Try to restore the previous split offset. + var split_offset: float = split_container.get_child(1).size.x + split_container.split_offset = split_offset + split_container.move_child(outline_container, 1) + else: + split_container.move_child(outline_container, 0) + +func update_script_list_visibility(): + scripts_item_list.get_parent().visible = is_script_list_visible + +func create_editor_texture(texture: Texture2D) -> Texture2D: + var image: Image = texture.get_image().duplicate() + image.adjust_bcs(1.0, 1.0, get_editor_icon_saturation()) + + return ImageTexture.create_from_image(image) + +func sync_settings(): + if (suppress_settings_sync): + return + + var changed_settings: PackedStringArray = get_editor_settings().get_changed_settings() + for setting: String in changed_settings: + if (setting == "interface/theme/icon_saturation"): + init_icons() + engine_func_btn.icon = engine_func_icon + func_btn.icon = func_icon + signal_btn.icon = signal_icon + export_btn.icon = export_icon + property_btn.icon = property_icon + class_btn.icon = class_icon + constant_btn.icon = constant_icon + update_outline() + continue + + if (!setting.begins_with(SCRIPT_IDE)): + continue + + if (setting == OUTLINE_POSITION_RIGHT): + var new_outline_right: bool = get_setting(OUTLINE_POSITION_RIGHT, is_outline_right) + if (new_outline_right != is_outline_right): + is_outline_right = new_outline_right + + update_outline_position() + elif (setting == OUTLINE_ORDER): + update_outline_order() + update_outline_button_order() + update_outline() + elif (setting == HIDE_PRIVATE_MEMBERS): + var new_hide_private_members: bool = get_setting(HIDE_PRIVATE_MEMBERS, hide_private_members) + if (new_hide_private_members != hide_private_members): + hide_private_members = new_hide_private_members + + update_outline_cache() + update_outline() + elif (setting == SCRIPT_LIST_VISIBLE): + var new_script_list_visible: bool = get_setting(SCRIPT_LIST_VISIBLE, is_script_list_visible) + if (new_script_list_visible != is_script_list_visible): + is_script_list_visible = new_script_list_visible + + update_script_list_visibility() + elif (setting == SCRIPT_TABS_VISIBLE): + var new_script_tabs_visible: bool = get_setting(SCRIPT_TABS_VISIBLE, is_script_tabs_visible) + if (new_script_tabs_visible != is_script_tabs_visible): + is_script_tabs_visible = new_script_tabs_visible + + scripts_tab_container.tabs_visible = is_script_tabs_visible + elif (setting == SCRIPT_TAB_POSITION_TOP): + var new_script_tabs_top: bool = get_setting(SCRIPT_TAB_POSITION_TOP, is_script_tabs_top) + if (new_script_tabs_top != is_script_tabs_top): + is_script_tabs_top = new_script_tabs_top + + update_tabs_position() + elif (setting == AUTO_NAVIGATE_IN_FS): + is_auto_navigate_in_fs = get_setting(AUTO_NAVIGATE_IN_FS, is_auto_navigate_in_fs) + elif (setting == OPEN_OUTLINE_POPUP): + open_outline_popup_shc = get_shortcut(OPEN_OUTLINE_POPUP) + elif (setting == OPEN_SCRIPTS_POPUP): + open_scripts_popup_shc = get_shortcut(OPEN_SCRIPTS_POPUP) + elif (setting == OPEN_OVERRIDE_POPUP): + open_override_popup_shc = get_shortcut(OPEN_OVERRIDE_POPUP) + elif (setting == TAB_CYCLE_FORWARD): + tab_cycle_forward_shc = get_shortcut(TAB_CYCLE_FORWARD) + elif (setting == TAB_CYCLE_BACKWARD): + tab_cycle_backward_shc = get_shortcut(TAB_CYCLE_BACKWARD) + else: + # Update filter buttons. + for btn_node: Node in filter_box.get_children(): + var btn: Button = btn_node + var property: StringName = btn.get_meta(&"property") + + btn.button_pressed = get_setting(property, btn.button_pressed) + +func get_setting(property: StringName, alt: bool) -> bool: + var editor_settings: EditorSettings = get_editor_settings() + if (editor_settings.has_setting(property)): + return editor_settings.get_setting(property) + else: + editor_settings.set_setting(property, alt) + return alt + +func set_setting(property: StringName, value: bool): + var editor_settings: EditorSettings = get_editor_settings() + + suppress_settings_sync = true + editor_settings.set_setting(property, value) + suppress_settings_sync = false + +func get_shortcut(property: StringName) -> Shortcut: + return get_editor_settings().get_setting(property) + +func on_tab_changed(index: int): + selected_tab = index; + + if (old_script_editor_base != null): + old_script_editor_base.edited_script_changed.disconnect(update_selected_tab) + old_script_editor_base = null + + var script_editor: ScriptEditor = EditorInterface.get_script_editor() + var script_editor_base: ScriptEditorBase = script_editor.get_current_editor() + + if (script_editor_base != null): + script_editor_base.edited_script_changed.connect(update_selected_tab) + + old_script_editor_base = script_editor_base + + sync_script_list = true + + if (is_auto_navigate_in_fs && script_editor.get_current_script() != null): + var file: String = script_editor.get_current_script().get_path() + + if (file.contains(BUILT_IN_SCRIPT)): + # We navigate to the scene in case of a built-in script. + file = file.get_slice(BUILT_IN_SCRIPT, 0) + + file_to_navigate = file + else: + file_to_navigate = &"" + + schedule_update() + +func update_selected_tab(): + if (selected_tab == -1): + return + + if (scripts_item_list.item_count == 0): + return + + update_tab(selected_tab) + +func update_tabs(): + for index: int in scripts_tab_container.get_tab_count(): + update_tab(index) + +func update_tab(index: int): + scripts_tab_container.set_tab_title(index, scripts_item_list.get_item_text(index)) + scripts_tab_container.set_tab_icon(index, scripts_item_list.get_item_icon(index)) + scripts_tab_container.set_tab_tooltip(index, scripts_item_list.get_item_tooltip(index)) + +func update_tabs_position(): + if (is_script_tabs_top): + scripts_tab_container.tabs_position = TabContainer.POSITION_TOP + else: + scripts_tab_container.tabs_position = TabContainer.POSITION_BOTTOM + +func update_keywords(script: Script): + if (script == null): + return + + var new_script_type: StringName = script.get_instance_base_type() + if (old_script_type != new_script_type): + old_script_type = new_script_type + + keywords.clear() + keywords["_static_init"] = 0 + register_virtual_methods(new_script_type) + +func register_virtual_methods(clazz: String): + for method: Dictionary in ClassDB.class_get_method_list(clazz): + if (method[&"flags"] & METHOD_FLAG_VIRTUAL > 0): + keywords[method[&"name"]] = 0 + +func update_outline_cache(): + outline_cache = null + + var script: Script = get_current_script() + if (!script): + return + + update_keywords(script) + + # Check if built-in script. In this case we need to duplicate it for whatever reason. + if (script.get_path().contains(BUILT_IN_SCRIPT)): + script = script.duplicate() + + outline_cache = OutlineCache.new() + + # Collect all script members. + for_each_script_member(script, func(array: Array[String], item: String): array.append(item)) + + # Remove script members that only exist in the base script (which includes the base of the base etc.). + # Note: The method that only collects script members without including the base script(s) + # is not exposed to GDScript. + var base_script: Script = script.get_base_script() + if (base_script != null): + for_each_script_member(base_script, func(array: Array[String], item: String): array.erase(item)) + +func for_each_script_member(script: Script, consumer: Callable): + # Functions / Methods + for dict: Dictionary in script.get_script_method_list(): + var func_name: String = dict[&"name"] + + if (keywords.has(func_name)): + consumer.call(outline_cache.engine_funcs, func_name) + else: + if hide_private_members && func_name.begins_with(UNDERSCORE): + continue + + # Inline getter/setter will normally be shown as '@...getter', '@...setter'. + # Since we already show the variable itself, we will skip those. + if (func_name.begins_with(INLINE)): + continue + + consumer.call(outline_cache.funcs, func_name) + + # Properties / Exported variables + for dict: Dictionary in script.get_script_property_list(): + var property: String = dict[&"name"] + if hide_private_members && property.begins_with(UNDERSCORE): + continue + + var usage: int = dict[&"usage"] + + if (usage & PROPERTY_USAGE_SCRIPT_VARIABLE): + if (usage & PROPERTY_USAGE_STORAGE && usage & PROPERTY_USAGE_EDITOR): + consumer.call(outline_cache.exports, property) + else: + consumer.call(outline_cache.properties, property) + + # Static variables (are separated for whatever reason) + for dict: Dictionary in script.get_property_list(): + var property: String = dict[&"name"] + if hide_private_members && property.begins_with(UNDERSCORE): + continue + + var usage: int = dict[&"usage"] + + if (usage & PROPERTY_USAGE_SCRIPT_VARIABLE): + consumer.call(outline_cache.properties, property) + + # Signals + for dict: Dictionary in script.get_script_signal_list(): + var signal_name: String = dict[&"name"] + + consumer.call(outline_cache.signals, signal_name) + + # Constants / Classes + for name_key: String in script.get_script_constant_map(): + if hide_private_members && name_key.begins_with(UNDERSCORE): + continue + + var object: Variant = script.get_script_constant_map().get(name_key) + # Inner classes have no source code, while a const of type GDScript has. + if (object is GDScript && !object.has_source_code()): + consumer.call(outline_cache.classes, name_key) + else: + consumer.call(outline_cache.constants, name_key) + +func update_outline(): + outline.clear() + + if (outline_cache == null): + return + + for outline_type: OutlineType in outline_type_order: + outline_type.add_to_outline.call() + +func add_to_outline(items: Array[String], icon: Texture2D, type: StringName, modifier: StringName = &""): + add_to_outline_ext(items, func(str: String): return icon, type, modifier) + +func add_to_outline_ext(items: Array[String], icon_callable: Callable, type: StringName, modifier: StringName = &""): + var text: String = outline_filter_txt.get_text() + + if (is_sorted()): + items = items.duplicate() + items.sort_custom(func(str1: String, str2: String): return str1.naturalnocasecmp_to(str2) < 0) + + for item: String in items: + if (text.is_empty() || text.is_subsequence_ofn(item)): + var icon: Texture2D = icon_callable.call(item) + outline.add_item(item, icon, true) + + var dict: Dictionary[StringName, StringName] = { + &"type": type, + &"modifier": modifier + } + outline.set_item_metadata(outline.item_count - 1, dict) + +func get_func_icon(func_name: String) -> Texture2D: + var icon: Texture2D = func_icon + if (func_name.begins_with(GETTER)): + icon = func_get_icon + elif (func_name.begins_with(SETTER)): + icon = func_set_icon + + return icon + +func sync_tab_with_script_list(): + # For some reason the selected tab is wrong. Looks like a Godot bug. + if (selected_tab >= scripts_item_list.item_count): + selected_tab = scripts_tab_bar.current_tab + + # Hide filter and outline for non .gd scripts. + var is_script: bool = get_current_script() != null + filter_box.visible = is_script + outline.visible = is_script + + # Sync with script item list. + if (selected_tab != -1 && scripts_item_list.item_count > 0 && !scripts_item_list.is_selected(selected_tab)): + scripts_item_list.select(selected_tab) + scripts_item_list.item_selected.emit(selected_tab) + + scripts_item_list.ensure_current_is_visible() + +func on_tab_bar_mouse_exited(): + last_tab_hovered = -1 + +func on_tab_hovered(idx: int): + last_tab_hovered = idx + +func on_tab_bar_gui_input(event: InputEvent): + if (last_tab_hovered == -1): + return + + if (event is InputEventMouseButton): + if event.is_pressed() and event.button_index == MOUSE_BUTTON_MIDDLE: + update_script_text_filter() + simulate_item_clicked(last_tab_hovered, MOUSE_BUTTON_MIDDLE) + + if (last_tab_hovered >= scripts_tab_bar.tab_count - 1): + last_tab_hovered = -1 + +func on_active_tab_rearranged(idx_to: int): + var control: Control = scripts_tab_container.get_tab_control(selected_tab) + if (!control): + return + + scripts_tab_container.move_child(control, idx_to) + scripts_tab_container.current_tab = scripts_tab_container.current_tab + selected_tab = scripts_tab_container.current_tab + +func get_res_path(idx: int) -> String: + var tab_control: Control = scripts_tab_container.get_tab_control(idx) + if (tab_control == null): + return '' + + var path_var: Variant = tab_control.get(&"metadata/_edit_res_path") + if (path_var == null): + return '' + + return path_var + +func on_tab_rmb(tab_idx: int): + update_script_text_filter() + simulate_item_clicked(tab_idx, MOUSE_BUTTON_RIGHT) + +func on_tab_close(tab_idx: int): + update_script_text_filter() + simulate_item_clicked(tab_idx, MOUSE_BUTTON_MIDDLE) + +func simulate_item_clicked(tab_idx: int, mouse_idx: int): + scripts_item_list.item_clicked.emit(tab_idx, scripts_item_list.get_local_mouse_position(), mouse_idx) + +func get_editor_scale() -> float: + return EditorInterface.get_editor_scale() + +func get_editor_corner_radius() -> int: + return EditorInterface.get_editor_settings().get_setting("interface/theme/corner_radius") + +func get_editor_accent_color() -> Color: + return EditorInterface.get_editor_settings().get_setting("interface/theme/accent_color") + +func get_editor_icon_saturation() -> float: + return EditorInterface.get_editor_settings().get_setting("interface/theme/icon_saturation") + +func is_sorted() -> bool: + return get_editor_settings().get_setting("text_editor/script_list/sort_members_outline_alphabetically") + +func get_editor_settings() -> EditorSettings: + return EditorInterface.get_editor_settings() + +func load_rel(path: String) -> Variant: + var script_path: String = get_script().get_path().get_base_dir() + return load(script_path.path_join(path)) + +static func find_or_null(arr: Array[Node], index: int = 0) -> Node: + if (arr.is_empty()): + push_error("""Node that is needed for Script-IDE not found. +Plugin will not work correctly. +This might be due to some other plugins or changes in the Engine. +Please report this to Script-IDE, so we can figure out a fix.""") + return null + return arr[index] + +## Cache for everything inside we collected to show in the Outline. +class OutlineCache: + var classes: Array[String] = [] + var constants: Array[String] = [] + var signals: Array[String] = [] + var exports: Array[String] = [] + var properties: Array[String] = [] + var funcs: Array[String] = [] + var engine_funcs: Array[String] = [] + +## Outline type for a concrete button with their items in the Outline. +class OutlineType: + var type_name: StringName + var add_to_outline: Callable + +## Contains everything we modify on the Tab Control. Used to save and restore the behaviour +## to keep the Engine in a clean state when the plugin is disabled. +class TabStateCache: + var tabs_visible: bool + var drag_to_rearrange_enabled: bool + var auto_translate_mode_state: Node.AutoTranslateMode + var tab_bar_drag_to_rearrange_enabled: bool + var tab_close_display_policy: TabBar.CloseButtonDisplayPolicy + var select_with_rmb: bool + + func save(tab_container: TabContainer, tab_bar: TabBar): + if (tab_container != null): + tabs_visible = tab_container.tabs_visible + drag_to_rearrange_enabled = tab_container.drag_to_rearrange_enabled + auto_translate_mode_state = tab_container.auto_translate_mode + if (tab_bar != null): + tab_bar_drag_to_rearrange_enabled = tab_bar.drag_to_rearrange_enabled + tab_close_display_policy = tab_bar.tab_close_display_policy + select_with_rmb = tab_bar.select_with_rmb + + func restore(tab_container: TabContainer, tab_bar: TabBar): + if (tab_container != null): + tab_container.tabs_visible = tabs_visible + tab_container.drag_to_rearrange_enabled = drag_to_rearrange_enabled + tab_container.auto_translate_mode = auto_translate_mode_state + if (tab_bar != null): + tab_bar.drag_to_rearrange_enabled = drag_to_rearrange_enabled + tab_bar.tab_close_display_policy = tab_close_display_policy + tab_bar.select_with_rmb = select_with_rmb diff --git a/hexmapper/addons/script-ide/plugin.gd.uid b/hexmapper/addons/script-ide/plugin.gd.uid new file mode 100644 index 0000000..f0f0e21 --- /dev/null +++ b/hexmapper/addons/script-ide/plugin.gd.uid @@ -0,0 +1 @@ +uid://bsbtldg1kikvd diff --git a/hexmapper/addons/script-ide/quickopen/quick_open_panel.gd b/hexmapper/addons/script-ide/quickopen/quick_open_panel.gd new file mode 100644 index 0000000..b79e898 --- /dev/null +++ b/hexmapper/addons/script-ide/quickopen/quick_open_panel.gd @@ -0,0 +1,229 @@ +## Quick open panel to quickly access all resources that are in the project. +## Initially shows all resources, but can be changed to more specific resources +## or filtered down with text. +@tool +extends PopupPanel + +const ADDONS: StringName = &"res://addons" +const SEPARATOR: StringName = &" - " +const STRUCTURE_START: StringName = &"(" +const STRUCTURE_END: StringName = &")" + +#region UI +@onready var filter_bar: TabBar = %FilterBar +@onready var search_option_btn: OptionButton = %SearchOptionBtn +@onready var filter_txt: LineEdit = %FilterTxt +@onready var files_list: ItemList = %FilesList +#endregion + +var plugin: EditorPlugin + +var scenes: Array[FileData] +var scripts: Array[FileData] +var resources: Array[FileData] +var others: Array[FileData] + +# For performance and memory considerations, we add all files into one reusable array. +var all_files: Array[FileData] + +var is_rebuild_cache: bool = true + +#region Plugin and Shortcut processing +func _ready() -> void: + files_list.item_selected.connect(open_file) + search_option_btn.item_selected.connect(rebuild_cache_and_ui.unbind(1)) + filter_txt.text_changed.connect(fill_files_list.unbind(1)) + + filter_bar.tab_changed.connect(change_fill_files_list.unbind(1)) + + about_to_popup.connect(on_show) + + var file_system: EditorFileSystem = EditorInterface.get_resource_filesystem() + file_system.filesystem_changed.connect(schedule_rebuild) + + if (plugin != null): + filter_txt.gui_input.connect(plugin.navigate_on_list.bind(files_list, open_file)) + +func _shortcut_input(event: InputEvent) -> void: + if (!event.is_pressed() || event.is_echo()): + return + + if (plugin.tab_cycle_forward_shc.matches_event(event)): + get_viewport().set_input_as_handled() + + var new_tab: int = filter_bar.current_tab + 1 + if (new_tab == filter_bar.get_tab_count()): + new_tab = 0 + filter_bar.current_tab = new_tab + elif (plugin.tab_cycle_backward_shc.matches_event(event)): + get_viewport().set_input_as_handled() + + var new_tab: int = filter_bar.current_tab - 1 + if (new_tab == -1): + new_tab = filter_bar.get_tab_count() - 1 + filter_bar.current_tab = new_tab +#endregion + +func open_file(index: int): + hide() + + var file: String = files_list.get_item_metadata(index) + + if (ResourceLoader.exists(file)): + var res: Resource = load(file) + EditorInterface.edit_resource(res) + + if (res is PackedScene): + EditorInterface.open_scene_from_path(file) + +func schedule_rebuild(): + is_rebuild_cache = true + +func on_show(): + if (search_option_btn.selected != 0): + search_option_btn.selected = 0 + + is_rebuild_cache = true + + var rebuild_ui: bool = false + var all_tab_not_pressed: bool = filter_bar.current_tab != 0 + rebuild_ui = is_rebuild_cache || all_tab_not_pressed + + if (is_rebuild_cache): + rebuild_cache() + + if (rebuild_ui): + if (all_tab_not_pressed): + # Triggers the ui update. + filter_bar.current_tab = 0 + else: + fill_files_list() + + filter_txt.select_all() + focus_and_select_first() + +func rebuild_cache(): + is_rebuild_cache = false + + all_files.clear() + scenes.clear() + scripts.clear() + resources.clear() + others.clear() + + build_file_cache() + +func rebuild_cache_and_ui(): + rebuild_cache() + fill_files_list() + + focus_and_select_first() + +func focus_and_select_first(): + filter_txt.grab_focus() + + if (files_list.item_count > 0): + files_list.select(0) + +func build_file_cache(): + var dir: EditorFileSystemDirectory = EditorInterface.get_resource_filesystem().get_filesystem() + build_file_cache_dir(dir) + + all_files.append_array(scenes) + all_files.append_array(scripts) + all_files.append_array(resources) + all_files.append_array(others) + +func build_file_cache_dir(dir: EditorFileSystemDirectory): + for index: int in dir.get_subdir_count(): + build_file_cache_dir(dir.get_subdir(index)) + + for index: int in dir.get_file_count(): + var file: String = dir.get_file_path(index) + if (search_option_btn.get_selected_id() == 0 && file.begins_with(ADDONS)): + continue + + var last_delimiter: int = file.rfind(&"/") + + var file_name: String = file.substr(last_delimiter + 1) + var file_structure: String = &"" + if (file_name.length() + 6 != file.length()): + file_structure = SEPARATOR + STRUCTURE_START + file.substr(6, last_delimiter - 6) + STRUCTURE_END + + var file_data: FileData = FileData.new() + file_data.file = file + file_data.file_name = file_name + file_data.file_name_structure = file_name + file_structure + file_data.file_type = dir.get_file_type(index) + + # Needed, as otherwise we have no icon. + if (file_data.file_type == &"Resource"): + file_data.file_type = &"Object" + + match (file.get_extension()): + &"tscn": scenes.append(file_data) + &"gd": scripts.append(file_data) + &"tres": resources.append(file_data) + &"gdshader": resources.append(file_data) + _: others.append(file_data) + +func change_fill_files_list(): + fill_files_list() + + focus_and_select_first() + +func fill_files_list(): + files_list.clear() + + if (filter_bar.current_tab == 0): + fill_files_list_with(all_files) + elif (filter_bar.current_tab == 1): + fill_files_list_with(scenes) + elif (filter_bar.current_tab == 2): + fill_files_list_with(scripts) + elif (filter_bar.current_tab == 3): + fill_files_list_with(resources) + elif (filter_bar.current_tab == 4): + fill_files_list_with(others) + +func fill_files_list_with(files: Array[FileData]): + var filter_text: String = filter_txt.text + files.sort_custom(sort_by_filter) + + for file_data: FileData in files: + var file: String = file_data.file + if (filter_text.is_empty() || filter_text.is_subsequence_ofn(file)): + var icon: Texture2D = EditorInterface.get_base_control().get_theme_icon(file_data.file_type, &"EditorIcons") + + files_list.add_item(file_data.file_name_structure, icon) + files_list.set_item_metadata(files_list.item_count - 1, file) + files_list.set_item_tooltip(files_list.item_count - 1, file) + +func sort_by_filter(file_data1: FileData, file_data2: FileData) -> bool: + var filter_text: String = filter_txt.text + var name1: String = file_data1.file_name + var name2: String = file_data2.file_name + + for index: int in filter_text.length(): + if (index >= name1.length()): + return true + if (index >= name2.length()): + return false + + var char: String = filter_text[index] + var a_match: bool = char== name1[index] + var b_match: bool = char == name2[index] + + if (a_match && !b_match): + return true + + if (b_match && !a_match): + return false + + return name1 < name2 + +class FileData: + var file: String + var file_name: String + var file_name_structure: String + var file_type: StringName diff --git a/hexmapper/addons/script-ide/quickopen/quick_open_panel.gd.uid b/hexmapper/addons/script-ide/quickopen/quick_open_panel.gd.uid new file mode 100644 index 0000000..ff2d1fe --- /dev/null +++ b/hexmapper/addons/script-ide/quickopen/quick_open_panel.gd.uid @@ -0,0 +1 @@ +uid://cptkaq6lylye diff --git a/hexmapper/addons/script-ide/quickopen/quick_open_panel.tscn b/hexmapper/addons/script-ide/quickopen/quick_open_panel.tscn new file mode 100644 index 0000000..ab1d60b --- /dev/null +++ b/hexmapper/addons/script-ide/quickopen/quick_open_panel.tscn @@ -0,0 +1,148 @@ +[gd_scene load_steps=14 format=3 uid="uid://d2pttchmj3n7q"] + +[ext_resource type="Script" path="res://addons/script-ide/quickopen/quick_open_panel.gd" id="1_3tl1s"] + +[sub_resource type="Image" id="Image_dfysb"] +data = { +"data": PackedByteArray(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, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 16, 225, 225, 225, 134, 224, 224, 224, 209, 224, 224, 224, 245, 224, 224, 224, 245, 224, 224, 224, 208, 224, 224, 224, 131, 236, 236, 236, 13, 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, 224, 224, 224, 73, 224, 224, 224, 228, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 225, 225, 225, 225, 68, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 73, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 183, 224, 224, 224, 198, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 198, 224, 224, 224, 189, 224, 224, 224, 255, 224, 224, 224, 254, 224, 224, 224, 65, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 16, 224, 224, 224, 228, 224, 224, 224, 255, 224, 224, 224, 120, 226, 226, 226, 60, 224, 224, 224, 255, 225, 225, 225, 109, 225, 225, 225, 110, 224, 224, 224, 255, 226, 226, 226, 60, 224, 224, 224, 128, 224, 224, 224, 255, 225, 225, 225, 223, 234, 234, 234, 12, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 134, 224, 224, 224, 255, 225, 225, 225, 183, 255, 255, 255, 0, 224, 224, 224, 153, 224, 224, 224, 243, 255, 255, 255, 4, 255, 255, 255, 4, 224, 224, 224, 244, 225, 225, 225, 151, 255, 255, 255, 1, 225, 225, 225, 191, 224, 224, 224, 255, 225, 225, 225, 127, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 209, 224, 224, 224, 255, 224, 224, 224, 72, 255, 255, 255, 0, 224, 224, 224, 216, 224, 224, 224, 198, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 199, 224, 224, 224, 214, 255, 255, 255, 0, 226, 226, 226, 78, 224, 224, 224, 255, 224, 224, 224, 206, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 243, 224, 224, 224, 255, 226, 226, 226, 78, 255, 255, 255, 0, 224, 224, 224, 244, 225, 225, 225, 151, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 152, 224, 224, 224, 242, 255, 255, 255, 1, 227, 227, 227, 81, 224, 224, 224, 255, 224, 224, 224, 241, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 245, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 229, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 147, 225, 225, 225, 149, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 230, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 244, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 208, 224, 224, 224, 255, 224, 224, 224, 147, 224, 224, 224, 161, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 235, 224, 224, 224, 235, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 160, 225, 225, 225, 150, 224, 224, 224, 255, 224, 224, 224, 205, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 131, 224, 224, 224, 255, 224, 224, 224, 189, 255, 255, 255, 1, 224, 224, 224, 152, 224, 224, 224, 243, 255, 255, 255, 4, 255, 255, 255, 4, 224, 224, 224, 244, 225, 225, 225, 151, 255, 255, 255, 2, 225, 225, 225, 199, 224, 224, 224, 255, 225, 225, 225, 127, 255, 255, 255, 0, 255, 255, 255, 0, 236, 236, 236, 13, 224, 224, 224, 225, 224, 224, 224, 255, 224, 224, 224, 128, 225, 225, 225, 67, 224, 224, 224, 255, 225, 225, 225, 110, 226, 226, 226, 111, 224, 224, 224, 255, 225, 225, 225, 67, 225, 225, 225, 135, 224, 224, 224, 255, 224, 224, 224, 221, 234, 234, 234, 12, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 68, 224, 224, 224, 254, 224, 224, 224, 255, 224, 224, 224, 194, 224, 224, 224, 220, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 219, 224, 224, 224, 196, 224, 224, 224, 255, 224, 224, 224, 253, 227, 227, 227, 62, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 66, 224, 224, 224, 225, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 220, 226, 226, 226, 61, 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, 237, 237, 237, 14, 224, 224, 224, 130, 224, 224, 224, 206, 224, 224, 224, 244, 224, 224, 224, 244, 224, 224, 224, 205, 225, 225, 225, 124, 230, 230, 230, 10, 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, 255, 255, 255, 0, 255, 255, 255, 0), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id="ImageTexture_p6ab8"] +image = SubResource("Image_dfysb") + +[sub_resource type="Image" id="Image_blafy"] +data = { +"data": PackedByteArray(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, 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, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 25, 226, 226, 226, 70, 229, 229, 229, 39, 255, 255, 255, 0, 226, 226, 226, 103, 224, 224, 224, 219, 224, 224, 224, 156, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 26, 225, 225, 225, 25, 255, 255, 255, 0, 224, 224, 224, 74, 224, 224, 224, 177, 226, 226, 226, 111, 255, 255, 255, 0, 224, 224, 224, 98, 224, 224, 224, 255, 225, 225, 225, 182, 255, 255, 255, 0, 228, 228, 228, 46, 224, 224, 224, 255, 224, 224, 224, 197, 255, 255, 255, 0, 224, 224, 224, 57, 224, 224, 224, 255, 224, 224, 224, 187, 255, 255, 255, 0, 225, 225, 225, 42, 224, 224, 224, 255, 224, 224, 224, 232, 255, 255, 255, 6, 224, 224, 224, 8, 225, 225, 225, 182, 224, 224, 224, 153, 255, 255, 255, 7, 255, 255, 255, 0, 228, 228, 228, 37, 255, 255, 255, 7, 255, 255, 255, 0, 229, 229, 229, 19, 224, 224, 224, 237, 224, 224, 224, 198, 225, 225, 225, 17, 255, 255, 255, 0, 227, 227, 227, 71, 224, 224, 224, 48, 255, 255, 255, 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, 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, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 228, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 73, 224, 224, 224, 226, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 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_bbwjp"] +image = SubResource("Image_blafy") + +[sub_resource type="Image" id="Image_4wc14"] +data = { +"data": PackedByteArray(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, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 33, 224, 224, 224, 255, 224, 224, 224, 255, 231, 231, 231, 31, 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, 226, 226, 226, 95, 224, 224, 224, 57, 255, 255, 255, 0, 224, 224, 224, 99, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 93, 255, 255, 255, 0, 224, 224, 224, 57, 224, 224, 224, 90, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 93, 224, 224, 224, 255, 224, 224, 224, 254, 224, 224, 224, 165, 224, 224, 224, 217, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 214, 225, 225, 225, 167, 224, 224, 224, 254, 224, 224, 224, 254, 224, 224, 224, 88, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 228, 228, 228, 55, 224, 224, 224, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 253, 225, 225, 225, 51, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 166, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 160, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 33, 224, 224, 224, 99, 224, 224, 224, 217, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 186, 224, 224, 224, 32, 224, 224, 224, 33, 224, 224, 224, 187, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 215, 224, 224, 224, 98, 224, 224, 224, 32, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 33, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 36, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 33, 255, 255, 255, 0, 255, 255, 255, 0, 229, 229, 229, 38, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 231, 231, 231, 31, 226, 226, 226, 95, 224, 224, 224, 216, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 187, 225, 225, 225, 34, 226, 226, 226, 35, 224, 224, 224, 192, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 213, 226, 226, 226, 95, 231, 231, 231, 31, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 166, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 163, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 57, 224, 224, 224, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 254, 227, 227, 227, 54, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 90, 224, 224, 224, 254, 224, 224, 224, 253, 224, 224, 224, 161, 225, 225, 225, 215, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 213, 224, 224, 224, 162, 224, 224, 224, 253, 224, 224, 224, 253, 226, 226, 226, 86, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 88, 225, 225, 225, 51, 255, 255, 255, 0, 224, 224, 224, 98, 224, 224, 224, 255, 224, 224, 224, 255, 226, 226, 226, 95, 255, 255, 255, 0, 227, 227, 227, 53, 226, 226, 226, 86, 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, 224, 224, 224, 32, 224, 224, 224, 255, 224, 224, 224, 255, 231, 231, 231, 31, 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, 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_ghict"] +image = SubResource("Image_4wc14") + +[sub_resource type="Image" id="Image_7rebo"] +data = { +"data": PackedByteArray(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, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 224, 224, 224, 99, 224, 224, 224, 213, 224, 224, 224, 212, 224, 224, 224, 97, 255, 255, 255, 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, 4, 224, 224, 224, 99, 224, 224, 224, 222, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 220, 224, 224, 224, 97, 255, 255, 255, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 4, 224, 224, 224, 99, 224, 224, 224, 222, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 213, 226, 226, 226, 87, 224, 224, 224, 88, 224, 224, 224, 214, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 220, 224, 224, 224, 97, 255, 255, 255, 4, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 199, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 215, 224, 224, 224, 89, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 224, 224, 224, 90, 224, 224, 224, 216, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 194, 255, 255, 255, 0, 255, 255, 255, 4, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 221, 224, 224, 224, 99, 255, 255, 255, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 5, 225, 225, 225, 101, 225, 225, 225, 223, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 3, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 213, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 222, 225, 225, 225, 100, 225, 225, 225, 100, 225, 225, 225, 223, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 3, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 2, 226, 226, 226, 87, 224, 224, 224, 213, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 2, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 2, 226, 226, 226, 87, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 1, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 100, 255, 255, 255, 5, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 196, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 223, 225, 225, 225, 101, 255, 255, 255, 5, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 193, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 3, 225, 225, 225, 93, 224, 224, 224, 218, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 223, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 216, 225, 225, 225, 91, 255, 255, 255, 2, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 3, 225, 225, 225, 93, 224, 224, 224, 218, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 216, 225, 225, 225, 91, 255, 255, 255, 2, 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, 3, 225, 225, 225, 93, 224, 224, 224, 208, 225, 225, 225, 207, 225, 225, 225, 91, 255, 255, 255, 2, 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, 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_grjtr"] +image = SubResource("Image_7rebo") + +[sub_resource type="Image" id="Image_e7nb8"] +data = { +"data": PackedByteArray(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, 224, 224, 224, 184, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 181, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 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, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 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, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 77, 225, 225, 225, 76, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 8, 224, 224, 224, 222, 224, 224, 224, 221, 224, 224, 224, 8, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 120, 224, 224, 224, 32, 224, 224, 224, 128, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 127, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 226, 226, 226, 35, 224, 224, 224, 248, 224, 224, 224, 195, 224, 224, 224, 247, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 247, 225, 225, 225, 34, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 224, 224, 224, 180, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 178, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 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, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 181, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 180, 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_xupch"] +image = SubResource("Image_e7nb8") + +[sub_resource type="Image" id="Image_gfvg1"] +data = { +"data": PackedByteArray(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, 255, 255, 255, 0, 225, 225, 225, 68, 224, 224, 224, 184, 224, 224, 224, 240, 224, 224, 224, 232, 224, 224, 224, 186, 227, 227, 227, 62, 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, 224, 224, 224, 129, 224, 224, 224, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 122, 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, 225, 225, 225, 68, 224, 224, 224, 254, 224, 224, 224, 254, 224, 224, 224, 123, 224, 224, 224, 32, 224, 224, 224, 33, 225, 225, 225, 125, 224, 224, 224, 254, 224, 224, 224, 254, 226, 226, 226, 69, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 184, 224, 224, 224, 255, 224, 224, 224, 123, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 225, 225, 225, 125, 224, 224, 224, 255, 225, 225, 225, 174, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 240, 224, 224, 224, 255, 231, 231, 231, 31, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 226, 226, 226, 35, 224, 224, 224, 255, 224, 224, 224, 233, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 232, 224, 224, 224, 255, 224, 224, 224, 32, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 228, 228, 228, 37, 224, 224, 224, 255, 224, 224, 224, 228, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 186, 224, 224, 224, 255, 224, 224, 224, 123, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 130, 224, 224, 224, 255, 224, 224, 224, 173, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 227, 227, 227, 62, 224, 224, 224, 255, 224, 224, 224, 254, 225, 225, 225, 126, 225, 225, 225, 34, 227, 227, 227, 36, 224, 224, 224, 131, 224, 224, 224, 255, 224, 224, 224, 255, 226, 226, 226, 77, 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, 224, 224, 224, 122, 224, 224, 224, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 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, 226, 226, 226, 69, 225, 225, 225, 174, 224, 224, 224, 233, 224, 224, 224, 228, 224, 224, 224, 173, 226, 226, 226, 77, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 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, 231, 231, 231, 21, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 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, 231, 231, 231, 21, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 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, 231, 231, 231, 21, 224, 224, 224, 210, 224, 224, 224, 227, 225, 225, 225, 34, 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, 231, 231, 231, 21, 225, 225, 225, 34, 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_w6vkw"] +image = SubResource("Image_gfvg1") + +[node name="QuickOpenPanel" type="PopupPanel"] +size = Vector2i(624, 100) +visible = true +script = ExtResource("1_3tl1s") + +[node name="PanelContainer" type="PanelContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 4.0 +offset_top = 4.0 +offset_right = -4.0 +offset_bottom = -4.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="MarginContainer" type="MarginContainer" parent="PanelContainer"] +layout_mode = 2 +theme_override_constants/margin_left = 5 +theme_override_constants/margin_top = 5 +theme_override_constants/margin_right = 5 +theme_override_constants/margin_bottom = 5 + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"] +layout_mode = 2 +theme_override_constants/separation = 5 + +[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 4 + +[node name="FilterBar" type="TabBar" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +current_tab = 0 +clip_tabs = false +scrolling_enabled = false +tab_count = 5 +tab_0/title = "All" +tab_0/icon = SubResource("ImageTexture_p6ab8") +tab_1/title = "Scene" +tab_1/icon = SubResource("ImageTexture_bbwjp") +tab_2/title = "GDscript" +tab_2/icon = SubResource("ImageTexture_ghict") +tab_3/title = "Resource" +tab_3/icon = SubResource("ImageTexture_grjtr") +tab_4/title = "Other" +tab_4/icon = SubResource("ImageTexture_xupch") + +[node name="SearchOptionBtn" type="OptionButton" parent="PanelContainer/MarginContainer/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +selected = 0 +item_count = 2 +popup/item_0/text = "Project" +popup/item_0/id = 0 +popup/item_1/text = "Project+Addons" +popup/item_1/id = 1 + +[node name="FilterTxt" type="LineEdit" parent="PanelContainer/MarginContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +placeholder_text = "Filter files" +right_icon = SubResource("ImageTexture_w6vkw") + +[node name="FilesList" type="ItemList" parent="PanelContainer/MarginContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 +allow_reselect = true diff --git a/hexmapper/assets/spritesheets/map_buildings_72x72_mapping.txt b/hexmapper/assets/spritesheets/map_buildings_72x72_mapping.txt new file mode 100644 index 0000000..518bcda --- /dev/null +++ b/hexmapper/assets/spritesheets/map_buildings_72x72_mapping.txt @@ -0,0 +1,3 @@ +x_col,y_col,tilename +0,0,Church5 +1,0,Church diff --git a/hexmapper/assets/spritesheets/map_buildings_72x72_spritesheet.png b/hexmapper/assets/spritesheets/map_buildings_72x72_spritesheet.png new file mode 100644 index 0000000..bc9cf5c Binary files /dev/null and b/hexmapper/assets/spritesheets/map_buildings_72x72_spritesheet.png differ diff --git a/hexmapper/assets/spritesheets/map_buildings_72x72_spritesheet.png.import b/hexmapper/assets/spritesheets/map_buildings_72x72_spritesheet.png.import new file mode 100644 index 0000000..143db62 --- /dev/null +++ b/hexmapper/assets/spritesheets/map_buildings_72x72_spritesheet.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bf0ux0t00blb7" +path="res://.godot/imported/map_buildings_72x72_spritesheet.png-45a1b45b054710c4965d93406f6cad94.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/spritesheets/map_buildings_72x72_spritesheet.png" +dest_files=["res://.godot/imported/map_buildings_72x72_spritesheet.png-45a1b45b054710c4965d93406f6cad94.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/hexmapper/assets/spritesheets/map_hex_terrain_72x72_mapping.txt b/hexmapper/assets/spritesheets/map_hex_terrain_72x72_mapping.txt new file mode 100644 index 0000000..ef3b089 --- /dev/null +++ b/hexmapper/assets/spritesheets/map_hex_terrain_72x72_mapping.txt @@ -0,0 +1,51 @@ +x_col,y_col,tilename +0,0,Grass1 +1,0,WoodsDark1 +2,0,LightGrass1 +3,0,BrownHills2 +4,0,Rough2 +5,0,Water2 +6,0,Lake1 +7,0,Orchards2 +0,1,Ocean2 +1,1,Woods1 +2,1,DesertScrub1 +3,1,Mud1 +4,1,SaltBush1 +5,1,Mountains1 +6,1,LowHills4 +7,1,LightGrass2 +0,2,Brambles1 +1,2,BoulderHills1 +2,2,Mud3 +3,2,LowHills2 +4,2,Mountains5 +5,2,Snow2 +6,2,Woods2 +7,2,Lake2 +0,3,DesertScrub4 +1,3,Snow1 +2,3,Brush2 +3,3,Rough1 +4,3,Ocean1 +5,3,DesertScrub2 +6,3,Hills1 +7,3,LowHills1 +0,4,Desert1 +1,4,Orchards1 +2,4,Desert2 +3,4,Brush3 +4,4,SaltBush2 +5,4,LowHills3 +6,4,BrownHills1 +7,4,HillsGreen3 +0,5,Water1 +1,5,WoodsDark2 +2,5,HillsGreen1 +3,5,Brush1 +4,5,Grass2 +5,5,Mud2 +6,5,HillsGreen2 +7,5,Hills3 +0,6,Mountains2 +1,6,Grass3 diff --git a/hexmapper/assets/spritesheets/map_hex_terrain_72x72_spritesheet.png b/hexmapper/assets/spritesheets/map_hex_terrain_72x72_spritesheet.png new file mode 100644 index 0000000..f926c60 Binary files /dev/null and b/hexmapper/assets/spritesheets/map_hex_terrain_72x72_spritesheet.png differ diff --git a/hexmapper/assets/spritesheets/map_hex_terrain_72x72_spritesheet.png.import b/hexmapper/assets/spritesheets/map_hex_terrain_72x72_spritesheet.png.import new file mode 100644 index 0000000..d3a60f5 --- /dev/null +++ b/hexmapper/assets/spritesheets/map_hex_terrain_72x72_spritesheet.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://berwv00k5ffjm" +path="res://.godot/imported/map_hex_terrain_72x72_spritesheet.png-86d1a5232aaa2514c77dfb3794ad75a8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/spritesheets/map_hex_terrain_72x72_spritesheet.png" +dest_files=["res://.godot/imported/map_hex_terrain_72x72_spritesheet.png-86d1a5232aaa2514c77dfb3794ad75a8.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/hexmapper/assets/spritesheets/ui_72x72_mapping.txt b/hexmapper/assets/spritesheets/ui_72x72_mapping.txt new file mode 100644 index 0000000..4d45b39 --- /dev/null +++ b/hexmapper/assets/spritesheets/ui_72x72_mapping.txt @@ -0,0 +1,2 @@ +x_col,y_col,tilename +0,0,hex_cursor \ No newline at end of file diff --git a/hexmapper/assets/spritesheets/ui_72x72_spritesheet.png b/hexmapper/assets/spritesheets/ui_72x72_spritesheet.png new file mode 100644 index 0000000..a4f5a7f Binary files /dev/null and b/hexmapper/assets/spritesheets/ui_72x72_spritesheet.png differ diff --git a/hexmapper/assets/spritesheets/ui_72x72_spritesheet.png.import b/hexmapper/assets/spritesheets/ui_72x72_spritesheet.png.import new file mode 100644 index 0000000..22e89c4 --- /dev/null +++ b/hexmapper/assets/spritesheets/ui_72x72_spritesheet.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cit5dnn6eoun1" +path="res://.godot/imported/ui_72x72_spritesheet.png-82a84268abb46eb82622740421239ffb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/spritesheets/ui_72x72_spritesheet.png" +dest_files=["res://.godot/imported/ui_72x72_spritesheet.png-82a84268abb46eb82622740421239ffb.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/hexmapper/assets/testing/test_atlas/test_atlas_1.png b/hexmapper/assets/testing/test_atlas/test_atlas_1.png new file mode 100644 index 0000000..c7eed9d Binary files /dev/null and b/hexmapper/assets/testing/test_atlas/test_atlas_1.png differ diff --git a/hexmapper/assets/testing/test_atlas/test_atlas_1.png.import b/hexmapper/assets/testing/test_atlas/test_atlas_1.png.import new file mode 100644 index 0000000..f7fbb8e --- /dev/null +++ b/hexmapper/assets/testing/test_atlas/test_atlas_1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bmoetibbicf2b" +path="res://.godot/imported/test_atlas_1.png-229dd4f6ec28e29b3d83370efb89ebf5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/testing/test_atlas/test_atlas_1.png" +dest_files=["res://.godot/imported/test_atlas_1.png-229dd4f6ec28e29b3d83370efb89ebf5.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/hexmapper/assets/testing/test_scene.tscn b/hexmapper/assets/testing/test_scene.tscn new file mode 100644 index 0000000..8f59c83 --- /dev/null +++ b/hexmapper/assets/testing/test_scene.tscn @@ -0,0 +1,37 @@ +[gd_scene load_steps=6 format=4 uid="uid://5nstm5lfne5o"] + +[ext_resource type="Texture2D" uid="uid://bmoetibbicf2b" path="res://assets/testing/test_atlas/test_atlas_1.png" id="1_rmkq0"] +[ext_resource type="Texture2D" uid="uid://bk6fgpn7v6gmw" path="res://assets/testing/test_tiles/grass_1.png" id="2_1178h"] + +[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_1178h"] +resource_name = "desert_1" +texture = ExtResource("1_rmkq0") +texture_region_size = Vector2i(72, 72) +0:0/0 = 0 +1:0/0 = 0 +2:0/0 = 0 +3:0/0 = 0 + +[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_qio7w"] +resource_name = "grass" +texture = ExtResource("2_1178h") +texture_region_size = Vector2i(72, 72) +0:0/0 = 0 + +[sub_resource type="TileSet" id="TileSet_qio7w"] +resource_name = "desert_2" +tile_shape = 3 +tile_layout = 5 +tile_offset_axis = 1 +tile_size = Vector2i(72, 72) +sources/48 = SubResource("TileSetAtlasSource_1178h") +sources/49 = SubResource("TileSetAtlasSource_qio7w") +tile_proxies/coords_level = [[24, Vector2i(0, 0)], [28, Vector2i(0, 0)], [25, Vector2i(0, 0)], [28, Vector2i(1, 0)], [26, Vector2i(0, 0)], [28, Vector2i(2, 0)], [27, Vector2i(0, 0)], [28, Vector2i(3, 0)], [39, Vector2i(0, 0)], [43, Vector2i(0, 0)], [40, Vector2i(0, 0)], [43, Vector2i(1, 0)], [41, Vector2i(0, 0)], [43, Vector2i(2, 0)], [42, Vector2i(0, 0)], [43, Vector2i(3, 0)], [44, Vector2i(0, 0)], [48, Vector2i(0, 0)], [45, Vector2i(0, 0)], [48, Vector2i(1, 0)], [46, Vector2i(0, 0)], [48, Vector2i(2, 0)], [47, Vector2i(0, 0)], [48, Vector2i(3, 0)]] + +[node name="Node2D" type="Node2D"] + +[node name="TileMapLayer" type="TileMapLayer" parent="."] +tile_map_data = PackedByteArray("AAABAAEAMAAAAAAAAAAAAAEAMAAAAAAAAAD//wEAMAAAAAAAAAD+/wEAMAAAAAAAAAD+/wIAMAAAAAAAAAD//wMAMAAAAAAAAAAAAAQAMAAAAAAAAAAAAAMAMAAAAAAAAAABAAMAMAAAAAAAAAACAAMAMAAAAAAAAAACAAIAMAAAAAAAAAABAAIAMAAAAAAAAAAAAAIAMAAAAAAAAAD//wIAMAAAAAAAAAD9/wIAMAAAAAAAAAD9/wMAMAAAAAAAAAD+/wMAMAAAAAAAAAD//wQAMAAAAAAAAAADAAMAMAAAAAAAAAACAAEAMAAAAAAAAAACAAAAMAAAAAAAAAACAP//MAADAAAAAAACAP7/MAADAAAAAAABAP3/MAADAAAAAAABAP7/MAAAAAAAAAD///z/MAADAAAAAAD///3/MAADAAAAAAAAAP7/MAADAAAAAAABAP//MAACAAAAAAACAP3/MAADAAAAAAABAPz/MAADAAAAAAAAAPz/MAADAAAAAAAAAP3/MAADAAAAAAD+//3/MAADAAAAAAD9//3/MAADAAAAAAD8//3/MAADAAAAAAD7//3/MAADAAAAAAD7//7/MAADAAAAAAD7////MAACAAAAAAD7/wAAMAADAAAAAAD8////MAACAAAAAAD8//7/MAADAAAAAAD9//7/MAADAAAAAAD+//z/MAADAAAAAAD+//7/MAADAAAAAAD///7/MAADAAAAAAABAAAAMAACAAAAAAAAAP//MAACAAAAAAAAAAAAMAACAAAAAAD/////MAACAAAAAAD+////MAACAAAAAAD//wAAMAACAAAAAAD9////MAACAAAAAAD9/wAAMAACAAAAAAD+/wAAMAACAAAAAAD8/wAAMAACAAAAAAD8/wEAMAACAAAAAAD9/wEAMAACAAAAAAD7/wEAMAACAAAAAAD6/wEAMAACAAAAAAD7/wIAMAACAAAAAAD8/wMAMAACAAAAAAD8/wIAMAACAAAAAAD6/wAAMAACAAAAAAD5////MAACAAAAAAD5//7/MAACAAAAAAD6////MAACAAAAAAD6//7/MAACAAAAAAD5/wAAMAACAAAAAAD5/wEAMAACAAAAAAD5/wIAMAACAAAAAAD6/wIAMAACAAAAAAD4/wEAMAACAAAAAAD4/wAAMAACAAAAAAD4////MAACAAAAAAD3////MAACAAAAAAD3/wAAMAACAAAAAAACAAYAMAABAAAAAAACAAUAMAABAAAAAAABAAQAMAABAAAAAAABAAUAMAABAAAAAAAAAAUAMAAAAAAAAAD+/wQAMAAAAAAAAAD+/wUAMAAAAAAAAAD//wUAMAAAAAAAAAD//wYAMAAAAAAAAAAAAAcAMAAAAAAAAAAAAAYAMAAAAAAAAAABAAYAMAAAAAAAAAD+/wYAMAAAAAAAAAD9/wUAMAAAAAAAAAD9/wQAMAAAAAAAAAACAAQAMAAAAAAAAAADAAQAMAAAAAAAAAAEAAQAMAAAAAAAAAAEAAMAMAAAAAAAAAAEAAIAMAAAAAAAAAADAAIAMAAAAAAAAAADAAEAMAAAAAAAAAAGAPn/MQAAAAAAAAAGAPj/MQAAAAAAAAAFAPj/MQAAAAAAAAA=") +tile_set = SubResource("TileSet_qio7w") + +[node name="Camera2D" type="Camera2D" parent="."] diff --git a/hexmapper/assets/testing/test_tiles/desert_1.png b/hexmapper/assets/testing/test_tiles/desert_1.png new file mode 100644 index 0000000..5f9de55 Binary files /dev/null and b/hexmapper/assets/testing/test_tiles/desert_1.png differ diff --git a/hexmapper/assets/testing/test_tiles/desert_1.png.import b/hexmapper/assets/testing/test_tiles/desert_1.png.import new file mode 100644 index 0000000..a8bcf28 --- /dev/null +++ b/hexmapper/assets/testing/test_tiles/desert_1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://djh0t5vrym3ah" +path="res://.godot/imported/desert_1.png-9c2f7978ad7b8984f766cd1605191ddd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/testing/test_tiles/desert_1.png" +dest_files=["res://.godot/imported/desert_1.png-9c2f7978ad7b8984f766cd1605191ddd.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/hexmapper/assets/testing/test_tiles/desert_2.png b/hexmapper/assets/testing/test_tiles/desert_2.png new file mode 100644 index 0000000..03296b6 Binary files /dev/null and b/hexmapper/assets/testing/test_tiles/desert_2.png differ diff --git a/hexmapper/assets/testing/test_tiles/desert_2.png.import b/hexmapper/assets/testing/test_tiles/desert_2.png.import new file mode 100644 index 0000000..100446c --- /dev/null +++ b/hexmapper/assets/testing/test_tiles/desert_2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://barsrx7grbd2v" +path="res://.godot/imported/desert_2.png-d0f4d80ecb261d17f80c9543f313d740.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/testing/test_tiles/desert_2.png" +dest_files=["res://.godot/imported/desert_2.png-d0f4d80ecb261d17f80c9543f313d740.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/hexmapper/assets/testing/test_tiles/grass_1.png b/hexmapper/assets/testing/test_tiles/grass_1.png new file mode 100644 index 0000000..55d8e8c Binary files /dev/null and b/hexmapper/assets/testing/test_tiles/grass_1.png differ diff --git a/hexmapper/assets/testing/test_tiles/grass_1.png.import b/hexmapper/assets/testing/test_tiles/grass_1.png.import new file mode 100644 index 0000000..1a8a7cb --- /dev/null +++ b/hexmapper/assets/testing/test_tiles/grass_1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bk6fgpn7v6gmw" +path="res://.godot/imported/grass_1.png-a3bba874e19d2d6c38da76061f183b6e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/testing/test_tiles/grass_1.png" +dest_files=["res://.godot/imported/grass_1.png-a3bba874e19d2d6c38da76061f183b6e.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/hexmapper/assets/testing/test_tiles/grass_2.png b/hexmapper/assets/testing/test_tiles/grass_2.png new file mode 100644 index 0000000..8730504 Binary files /dev/null and b/hexmapper/assets/testing/test_tiles/grass_2.png differ diff --git a/hexmapper/assets/testing/test_tiles/grass_2.png.import b/hexmapper/assets/testing/test_tiles/grass_2.png.import new file mode 100644 index 0000000..81c0e8b --- /dev/null +++ b/hexmapper/assets/testing/test_tiles/grass_2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d0er7xrdj8p6u" +path="res://.godot/imported/grass_2.png-e4e4c365daf011a3a978157ec3b769ee.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/testing/test_tiles/grass_2.png" +dest_files=["res://.godot/imported/grass_2.png-e4e4c365daf011a3a978157ec3b769ee.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/hexmapper/assets/theme/fonts/Caladea-Bold.ttf b/hexmapper/assets/theme/fonts/Caladea-Bold.ttf new file mode 100644 index 0000000..cc20223 Binary files /dev/null and b/hexmapper/assets/theme/fonts/Caladea-Bold.ttf differ diff --git a/hexmapper/assets/theme/fonts/Caladea-Bold.ttf.import b/hexmapper/assets/theme/fonts/Caladea-Bold.ttf.import new file mode 100644 index 0000000..86e4126 --- /dev/null +++ b/hexmapper/assets/theme/fonts/Caladea-Bold.ttf.import @@ -0,0 +1,35 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://3lmnwv7rgemx" +path="res://.godot/imported/Caladea-Bold.ttf-71a79ff4d6d88bc750b35fd77b87139e.fontdata" + +[deps] + +source_file="res://assets/theme/fonts/Caladea-Bold.ttf" +dest_files=["res://.godot/imported/Caladea-Bold.ttf-71a79ff4d6d88bc750b35fd77b87139e.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=4 +keep_rounding_remainders=true +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/hexmapper/assets/theme/fonts/Caladea-BoldItalic.ttf b/hexmapper/assets/theme/fonts/Caladea-BoldItalic.ttf new file mode 100644 index 0000000..6d1e8b5 Binary files /dev/null and b/hexmapper/assets/theme/fonts/Caladea-BoldItalic.ttf differ diff --git a/hexmapper/assets/theme/fonts/Caladea-BoldItalic.ttf.import b/hexmapper/assets/theme/fonts/Caladea-BoldItalic.ttf.import new file mode 100644 index 0000000..00412ca --- /dev/null +++ b/hexmapper/assets/theme/fonts/Caladea-BoldItalic.ttf.import @@ -0,0 +1,35 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://ds7uoarp6hdla" +path="res://.godot/imported/Caladea-BoldItalic.ttf-5dfbf5961fd6e4dc3af3356b93c89f17.fontdata" + +[deps] + +source_file="res://assets/theme/fonts/Caladea-BoldItalic.ttf" +dest_files=["res://.godot/imported/Caladea-BoldItalic.ttf-5dfbf5961fd6e4dc3af3356b93c89f17.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=4 +keep_rounding_remainders=true +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/hexmapper/assets/theme/fonts/Caladea-Italic.ttf b/hexmapper/assets/theme/fonts/Caladea-Italic.ttf new file mode 100644 index 0000000..83c526c Binary files /dev/null and b/hexmapper/assets/theme/fonts/Caladea-Italic.ttf differ diff --git a/hexmapper/assets/theme/fonts/Caladea-Italic.ttf.import b/hexmapper/assets/theme/fonts/Caladea-Italic.ttf.import new file mode 100644 index 0000000..ffb2929 --- /dev/null +++ b/hexmapper/assets/theme/fonts/Caladea-Italic.ttf.import @@ -0,0 +1,35 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://bgidwohif0o2m" +path="res://.godot/imported/Caladea-Italic.ttf-be311be29238988942d835a7caec1bb8.fontdata" + +[deps] + +source_file="res://assets/theme/fonts/Caladea-Italic.ttf" +dest_files=["res://.godot/imported/Caladea-Italic.ttf-be311be29238988942d835a7caec1bb8.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=4 +keep_rounding_remainders=true +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/hexmapper/assets/theme/fonts/Caladea-Regular.ttf b/hexmapper/assets/theme/fonts/Caladea-Regular.ttf new file mode 100644 index 0000000..64d38c6 Binary files /dev/null and b/hexmapper/assets/theme/fonts/Caladea-Regular.ttf differ diff --git a/hexmapper/assets/theme/fonts/Caladea-Regular.ttf.import b/hexmapper/assets/theme/fonts/Caladea-Regular.ttf.import new file mode 100644 index 0000000..f6990ff --- /dev/null +++ b/hexmapper/assets/theme/fonts/Caladea-Regular.ttf.import @@ -0,0 +1,35 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://nrtjvrmaiw20" +path="res://.godot/imported/Caladea-Regular.ttf-1981274936b347871ea809adf258b841.fontdata" + +[deps] + +source_file="res://assets/theme/fonts/Caladea-Regular.ttf" +dest_files=["res://.godot/imported/Caladea-Regular.ttf-1981274936b347871ea809adf258b841.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=4 +keep_rounding_remainders=true +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/hexmapper/assets/theme/fonts/OFL.txt b/hexmapper/assets/theme/fonts/OFL.txt new file mode 100644 index 0000000..38cd636 --- /dev/null +++ b/hexmapper/assets/theme/fonts/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2012 The Caladea Project Authors (https://github.com/huertatipografica/Caladea) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/hexmapper/assets/theme/fonts/TabulaPeutingeriana-ELv9.ttf b/hexmapper/assets/theme/fonts/TabulaPeutingeriana-ELv9.ttf new file mode 100644 index 0000000..629f70e Binary files /dev/null and b/hexmapper/assets/theme/fonts/TabulaPeutingeriana-ELv9.ttf differ diff --git a/hexmapper/assets/theme/fonts/TabulaPeutingeriana-ELv9.ttf.import b/hexmapper/assets/theme/fonts/TabulaPeutingeriana-ELv9.ttf.import new file mode 100644 index 0000000..1f0a502 --- /dev/null +++ b/hexmapper/assets/theme/fonts/TabulaPeutingeriana-ELv9.ttf.import @@ -0,0 +1,35 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://b7lyickfnampr" +path="res://.godot/imported/TabulaPeutingeriana-ELv9.ttf-72207fb0d8ef927106979dd9e7e2373a.fontdata" + +[deps] + +source_file="res://assets/theme/fonts/TabulaPeutingeriana-ELv9.ttf" +dest_files=["res://.godot/imported/TabulaPeutingeriana-ELv9.ttf-72207fb0d8ef927106979dd9e7e2373a.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=4 +keep_rounding_remainders=true +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/hexmapper/assets/theme/fonts/TabulaPeutingerianaCapitelBoldItalic-O14d.ttf b/hexmapper/assets/theme/fonts/TabulaPeutingerianaCapitelBoldItalic-O14d.ttf new file mode 100644 index 0000000..86f3ebf Binary files /dev/null and b/hexmapper/assets/theme/fonts/TabulaPeutingerianaCapitelBoldItalic-O14d.ttf differ diff --git a/hexmapper/assets/theme/fonts/TabulaPeutingerianaCapitelBoldItalic-O14d.ttf.import b/hexmapper/assets/theme/fonts/TabulaPeutingerianaCapitelBoldItalic-O14d.ttf.import new file mode 100644 index 0000000..e2a03f3 --- /dev/null +++ b/hexmapper/assets/theme/fonts/TabulaPeutingerianaCapitelBoldItalic-O14d.ttf.import @@ -0,0 +1,35 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://dumn3675wvp32" +path="res://.godot/imported/TabulaPeutingerianaCapitelBoldItalic-O14d.ttf-df36c7349c5e158e79039412c1b12d95.fontdata" + +[deps] + +source_file="res://assets/theme/fonts/TabulaPeutingerianaCapitelBoldItalic-O14d.ttf" +dest_files=["res://.godot/imported/TabulaPeutingerianaCapitelBoldItalic-O14d.ttf-df36c7349c5e158e79039412c1b12d95.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=4 +keep_rounding_remainders=true +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/hexmapper/assets/theme/fonts/info.txt b/hexmapper/assets/theme/fonts/info.txt new file mode 100644 index 0000000..4a77370 --- /dev/null +++ b/hexmapper/assets/theme/fonts/info.txt @@ -0,0 +1,2 @@ +license: Public Domain +link: https://www.fontspace.com/tabula-peutingeriana-font-f28431 \ No newline at end of file diff --git a/hexmapper/assets/theme/hexmapper_theme.tres b/hexmapper/assets/theme/hexmapper_theme.tres new file mode 100644 index 0000000..6ed97ba --- /dev/null +++ b/hexmapper/assets/theme/hexmapper_theme.tres @@ -0,0 +1,11 @@ +[gd_resource type="Theme" load_steps=2 format=3 uid="uid://cqh7512jkfhu3"] + +[ext_resource type="FontFile" uid="uid://nrtjvrmaiw20" path="res://assets/theme/fonts/Caladea-Regular.ttf" id="1_cbutr"] + +[resource] +Button/font_sizes/font_size = 24 +Button/fonts/font = ExtResource("1_cbutr") +Label/font_sizes/font_size = 24 +Label/fonts/font = ExtResource("1_cbutr") +OptionButton/font_sizes/font_size = 24 +OptionButton/fonts/font = ExtResource("1_cbutr") diff --git a/hexmapper/assets/tiles/BoulderHills1.png b/hexmapper/assets/tiles/BoulderHills1.png new file mode 100644 index 0000000..acdb5bc Binary files /dev/null and b/hexmapper/assets/tiles/BoulderHills1.png differ diff --git a/hexmapper/assets/tiles/BoulderHills1.png.import b/hexmapper/assets/tiles/BoulderHills1.png.import new file mode 100644 index 0000000..94772f8 --- /dev/null +++ b/hexmapper/assets/tiles/BoulderHills1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://baws66rpp3r45" +path="res://.godot/imported/BoulderHills1.png-3ee92d43833962adc5c138e74c73b76b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/BoulderHills1.png" +dest_files=["res://.godot/imported/BoulderHills1.png-3ee92d43833962adc5c138e74c73b76b.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/hexmapper/assets/tiles/Brambles1.png b/hexmapper/assets/tiles/Brambles1.png new file mode 100644 index 0000000..b0acde0 Binary files /dev/null and b/hexmapper/assets/tiles/Brambles1.png differ diff --git a/hexmapper/assets/tiles/Brambles1.png.import b/hexmapper/assets/tiles/Brambles1.png.import new file mode 100644 index 0000000..f4dd260 --- /dev/null +++ b/hexmapper/assets/tiles/Brambles1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ci2ukryno3di1" +path="res://.godot/imported/Brambles1.png-094b27f0e669afd063b1214a4b9de8fc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Brambles1.png" +dest_files=["res://.godot/imported/Brambles1.png-094b27f0e669afd063b1214a4b9de8fc.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/hexmapper/assets/tiles/BrownHills1.png b/hexmapper/assets/tiles/BrownHills1.png new file mode 100644 index 0000000..8e2b4ea Binary files /dev/null and b/hexmapper/assets/tiles/BrownHills1.png differ diff --git a/hexmapper/assets/tiles/BrownHills1.png.import b/hexmapper/assets/tiles/BrownHills1.png.import new file mode 100644 index 0000000..635013e --- /dev/null +++ b/hexmapper/assets/tiles/BrownHills1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dmwjgpnb0xo8o" +path="res://.godot/imported/BrownHills1.png-e6bfb8db22d358087a8e6c3601c2d5ad.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/BrownHills1.png" +dest_files=["res://.godot/imported/BrownHills1.png-e6bfb8db22d358087a8e6c3601c2d5ad.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/hexmapper/assets/tiles/BrownHills2.png b/hexmapper/assets/tiles/BrownHills2.png new file mode 100644 index 0000000..f43b4d2 Binary files /dev/null and b/hexmapper/assets/tiles/BrownHills2.png differ diff --git a/hexmapper/assets/tiles/BrownHills2.png.import b/hexmapper/assets/tiles/BrownHills2.png.import new file mode 100644 index 0000000..e89049a --- /dev/null +++ b/hexmapper/assets/tiles/BrownHills2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bwi2p0pey0d2m" +path="res://.godot/imported/BrownHills2.png-db97e6c20eaa024dedf7e0787313d629.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/BrownHills2.png" +dest_files=["res://.godot/imported/BrownHills2.png-db97e6c20eaa024dedf7e0787313d629.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/hexmapper/assets/tiles/Brush1.png b/hexmapper/assets/tiles/Brush1.png new file mode 100644 index 0000000..0315fbd Binary files /dev/null and b/hexmapper/assets/tiles/Brush1.png differ diff --git a/hexmapper/assets/tiles/Brush1.png.import b/hexmapper/assets/tiles/Brush1.png.import new file mode 100644 index 0000000..3d36f53 --- /dev/null +++ b/hexmapper/assets/tiles/Brush1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b0xhc1si2n8mq" +path="res://.godot/imported/Brush1.png-32cf27784eae2ca878388606a4476eaf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Brush1.png" +dest_files=["res://.godot/imported/Brush1.png-32cf27784eae2ca878388606a4476eaf.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/hexmapper/assets/tiles/Brush2.png b/hexmapper/assets/tiles/Brush2.png new file mode 100644 index 0000000..593c31c Binary files /dev/null and b/hexmapper/assets/tiles/Brush2.png differ diff --git a/hexmapper/assets/tiles/Brush2.png.import b/hexmapper/assets/tiles/Brush2.png.import new file mode 100644 index 0000000..f202c10 --- /dev/null +++ b/hexmapper/assets/tiles/Brush2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://vxfegypkmyju" +path="res://.godot/imported/Brush2.png-e5f6edaca5f73d52cfb88d3b256fdff4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Brush2.png" +dest_files=["res://.godot/imported/Brush2.png-e5f6edaca5f73d52cfb88d3b256fdff4.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/hexmapper/assets/tiles/Brush3.png b/hexmapper/assets/tiles/Brush3.png new file mode 100644 index 0000000..8d85a95 Binary files /dev/null and b/hexmapper/assets/tiles/Brush3.png differ diff --git a/hexmapper/assets/tiles/Brush3.png.import b/hexmapper/assets/tiles/Brush3.png.import new file mode 100644 index 0000000..76895f0 --- /dev/null +++ b/hexmapper/assets/tiles/Brush3.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cu5ivghabn1uc" +path="res://.godot/imported/Brush3.png-d1eab11389aeb7988f952b8032072539.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Brush3.png" +dest_files=["res://.godot/imported/Brush3.png-d1eab11389aeb7988f952b8032072539.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/hexmapper/assets/tiles/Desert1.png b/hexmapper/assets/tiles/Desert1.png new file mode 100644 index 0000000..5f9de55 Binary files /dev/null and b/hexmapper/assets/tiles/Desert1.png differ diff --git a/hexmapper/assets/tiles/Desert1.png.import b/hexmapper/assets/tiles/Desert1.png.import new file mode 100644 index 0000000..9002167 --- /dev/null +++ b/hexmapper/assets/tiles/Desert1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d1e47r7wba7u5" +path="res://.godot/imported/Desert1.png-a12712846d507831b8f9ac2d471b423c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Desert1.png" +dest_files=["res://.godot/imported/Desert1.png-a12712846d507831b8f9ac2d471b423c.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/hexmapper/assets/tiles/Desert2.png b/hexmapper/assets/tiles/Desert2.png new file mode 100644 index 0000000..03296b6 Binary files /dev/null and b/hexmapper/assets/tiles/Desert2.png differ diff --git a/hexmapper/assets/tiles/Desert2.png.import b/hexmapper/assets/tiles/Desert2.png.import new file mode 100644 index 0000000..608b29f --- /dev/null +++ b/hexmapper/assets/tiles/Desert2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dubugseywomk8" +path="res://.godot/imported/Desert2.png-7b0df9f870833b8f97cd1af52effc1a4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Desert2.png" +dest_files=["res://.godot/imported/Desert2.png-7b0df9f870833b8f97cd1af52effc1a4.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/hexmapper/assets/tiles/DesertScrub1.png b/hexmapper/assets/tiles/DesertScrub1.png new file mode 100644 index 0000000..6a0504b Binary files /dev/null and b/hexmapper/assets/tiles/DesertScrub1.png differ diff --git a/hexmapper/assets/tiles/DesertScrub1.png.import b/hexmapper/assets/tiles/DesertScrub1.png.import new file mode 100644 index 0000000..656254c --- /dev/null +++ b/hexmapper/assets/tiles/DesertScrub1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dl5gweu7hkygi" +path="res://.godot/imported/DesertScrub1.png-d72b2f21003a9645580328e2fefa5923.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/DesertScrub1.png" +dest_files=["res://.godot/imported/DesertScrub1.png-d72b2f21003a9645580328e2fefa5923.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/hexmapper/assets/tiles/DesertScrub2.png b/hexmapper/assets/tiles/DesertScrub2.png new file mode 100644 index 0000000..2009ce5 Binary files /dev/null and b/hexmapper/assets/tiles/DesertScrub2.png differ diff --git a/hexmapper/assets/tiles/DesertScrub2.png.import b/hexmapper/assets/tiles/DesertScrub2.png.import new file mode 100644 index 0000000..f2ecc37 --- /dev/null +++ b/hexmapper/assets/tiles/DesertScrub2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://crfrillu840hs" +path="res://.godot/imported/DesertScrub2.png-96527369dd672866ff90279f9b4a24d3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/DesertScrub2.png" +dest_files=["res://.godot/imported/DesertScrub2.png-96527369dd672866ff90279f9b4a24d3.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/hexmapper/assets/tiles/DesertScrub4.png b/hexmapper/assets/tiles/DesertScrub4.png new file mode 100644 index 0000000..fb888c5 Binary files /dev/null and b/hexmapper/assets/tiles/DesertScrub4.png differ diff --git a/hexmapper/assets/tiles/DesertScrub4.png.import b/hexmapper/assets/tiles/DesertScrub4.png.import new file mode 100644 index 0000000..772bbe4 --- /dev/null +++ b/hexmapper/assets/tiles/DesertScrub4.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d1jidyq14hvir" +path="res://.godot/imported/DesertScrub4.png-7f294947a2e2d7f5acc9c96a3ddcb104.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/DesertScrub4.png" +dest_files=["res://.godot/imported/DesertScrub4.png-7f294947a2e2d7f5acc9c96a3ddcb104.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/hexmapper/assets/tiles/Grass1.png b/hexmapper/assets/tiles/Grass1.png new file mode 100644 index 0000000..55d8e8c Binary files /dev/null and b/hexmapper/assets/tiles/Grass1.png differ diff --git a/hexmapper/assets/tiles/Grass1.png.import b/hexmapper/assets/tiles/Grass1.png.import new file mode 100644 index 0000000..e954f19 --- /dev/null +++ b/hexmapper/assets/tiles/Grass1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b5tpdsj6r1q66" +path="res://.godot/imported/Grass1.png-30a04a88466169a91f1cf1ca2c6c11fb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Grass1.png" +dest_files=["res://.godot/imported/Grass1.png-30a04a88466169a91f1cf1ca2c6c11fb.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/hexmapper/assets/tiles/Grass2.png b/hexmapper/assets/tiles/Grass2.png new file mode 100644 index 0000000..8730504 Binary files /dev/null and b/hexmapper/assets/tiles/Grass2.png differ diff --git a/hexmapper/assets/tiles/Grass2.png.import b/hexmapper/assets/tiles/Grass2.png.import new file mode 100644 index 0000000..86887b1 --- /dev/null +++ b/hexmapper/assets/tiles/Grass2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://db2wh5sody7rq" +path="res://.godot/imported/Grass2.png-d618be34b2012c09fbdb1c5ef19013bf.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Grass2.png" +dest_files=["res://.godot/imported/Grass2.png-d618be34b2012c09fbdb1c5ef19013bf.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/hexmapper/assets/tiles/Grass3.png b/hexmapper/assets/tiles/Grass3.png new file mode 100644 index 0000000..589c519 Binary files /dev/null and b/hexmapper/assets/tiles/Grass3.png differ diff --git a/hexmapper/assets/tiles/Grass3.png.import b/hexmapper/assets/tiles/Grass3.png.import new file mode 100644 index 0000000..05d0ba1 --- /dev/null +++ b/hexmapper/assets/tiles/Grass3.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bne7vb8psdwag" +path="res://.godot/imported/Grass3.png-f00b17931a597c8e0f903ee630d4c100.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Grass3.png" +dest_files=["res://.godot/imported/Grass3.png-f00b17931a597c8e0f903ee630d4c100.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/hexmapper/assets/tiles/Hills1.png b/hexmapper/assets/tiles/Hills1.png new file mode 100644 index 0000000..8a53fa9 Binary files /dev/null and b/hexmapper/assets/tiles/Hills1.png differ diff --git a/hexmapper/assets/tiles/Hills1.png.import b/hexmapper/assets/tiles/Hills1.png.import new file mode 100644 index 0000000..e011616 --- /dev/null +++ b/hexmapper/assets/tiles/Hills1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ctcup7v53kek1" +path="res://.godot/imported/Hills1.png-c264ba25edbaf9c3b62160eed388a3cb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Hills1.png" +dest_files=["res://.godot/imported/Hills1.png-c264ba25edbaf9c3b62160eed388a3cb.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/hexmapper/assets/tiles/Hills3.png b/hexmapper/assets/tiles/Hills3.png new file mode 100644 index 0000000..b3f8922 Binary files /dev/null and b/hexmapper/assets/tiles/Hills3.png differ diff --git a/hexmapper/assets/tiles/Hills3.png.import b/hexmapper/assets/tiles/Hills3.png.import new file mode 100644 index 0000000..ee70639 --- /dev/null +++ b/hexmapper/assets/tiles/Hills3.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bwqhcg0jd5xml" +path="res://.godot/imported/Hills3.png-dc5395484303ccdfac9cef469814e630.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Hills3.png" +dest_files=["res://.godot/imported/Hills3.png-dc5395484303ccdfac9cef469814e630.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/hexmapper/assets/tiles/HillsGreen1.png b/hexmapper/assets/tiles/HillsGreen1.png new file mode 100644 index 0000000..1c5980a Binary files /dev/null and b/hexmapper/assets/tiles/HillsGreen1.png differ diff --git a/hexmapper/assets/tiles/HillsGreen1.png.import b/hexmapper/assets/tiles/HillsGreen1.png.import new file mode 100644 index 0000000..73e4e4f --- /dev/null +++ b/hexmapper/assets/tiles/HillsGreen1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://3vaioopgry7c" +path="res://.godot/imported/HillsGreen1.png-a634db8c22e43716af34745e5dd39c3a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/HillsGreen1.png" +dest_files=["res://.godot/imported/HillsGreen1.png-a634db8c22e43716af34745e5dd39c3a.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/hexmapper/assets/tiles/HillsGreen2.png b/hexmapper/assets/tiles/HillsGreen2.png new file mode 100644 index 0000000..fa05a5a Binary files /dev/null and b/hexmapper/assets/tiles/HillsGreen2.png differ diff --git a/hexmapper/assets/tiles/HillsGreen2.png.import b/hexmapper/assets/tiles/HillsGreen2.png.import new file mode 100644 index 0000000..a76bc8c --- /dev/null +++ b/hexmapper/assets/tiles/HillsGreen2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://hhdsknelks3g" +path="res://.godot/imported/HillsGreen2.png-6cfb6f3094b0f541bf96f48513d6e370.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/HillsGreen2.png" +dest_files=["res://.godot/imported/HillsGreen2.png-6cfb6f3094b0f541bf96f48513d6e370.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/hexmapper/assets/tiles/HillsGreen3.png b/hexmapper/assets/tiles/HillsGreen3.png new file mode 100644 index 0000000..94bb10a Binary files /dev/null and b/hexmapper/assets/tiles/HillsGreen3.png differ diff --git a/hexmapper/assets/tiles/HillsGreen3.png.import b/hexmapper/assets/tiles/HillsGreen3.png.import new file mode 100644 index 0000000..f2b6f7a --- /dev/null +++ b/hexmapper/assets/tiles/HillsGreen3.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ds8gcjhqsehr" +path="res://.godot/imported/HillsGreen3.png-a0826550150ff9bbdd143cf702dd0181.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/HillsGreen3.png" +dest_files=["res://.godot/imported/HillsGreen3.png-a0826550150ff9bbdd143cf702dd0181.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/hexmapper/assets/tiles/Lake1.png b/hexmapper/assets/tiles/Lake1.png new file mode 100644 index 0000000..10d1d5e Binary files /dev/null and b/hexmapper/assets/tiles/Lake1.png differ diff --git a/hexmapper/assets/tiles/Lake1.png.import b/hexmapper/assets/tiles/Lake1.png.import new file mode 100644 index 0000000..1fb888c --- /dev/null +++ b/hexmapper/assets/tiles/Lake1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dq7u1rblad2dd" +path="res://.godot/imported/Lake1.png-7dab627b69d8ebf19906934d34562f42.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Lake1.png" +dest_files=["res://.godot/imported/Lake1.png-7dab627b69d8ebf19906934d34562f42.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/hexmapper/assets/tiles/Lake2.png b/hexmapper/assets/tiles/Lake2.png new file mode 100644 index 0000000..16fcf1e Binary files /dev/null and b/hexmapper/assets/tiles/Lake2.png differ diff --git a/hexmapper/assets/tiles/Lake2.png.import b/hexmapper/assets/tiles/Lake2.png.import new file mode 100644 index 0000000..aab8472 --- /dev/null +++ b/hexmapper/assets/tiles/Lake2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dmc5pajvlpkmw" +path="res://.godot/imported/Lake2.png-50921f08d39a3d9437742dcdf2b97765.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Lake2.png" +dest_files=["res://.godot/imported/Lake2.png-50921f08d39a3d9437742dcdf2b97765.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/hexmapper/assets/tiles/LightGrass1.png b/hexmapper/assets/tiles/LightGrass1.png new file mode 100644 index 0000000..6cb7c53 Binary files /dev/null and b/hexmapper/assets/tiles/LightGrass1.png differ diff --git a/hexmapper/assets/tiles/LightGrass1.png.import b/hexmapper/assets/tiles/LightGrass1.png.import new file mode 100644 index 0000000..851fc2d --- /dev/null +++ b/hexmapper/assets/tiles/LightGrass1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dq81v65rnbi7i" +path="res://.godot/imported/LightGrass1.png-2fd346f92ed520cff72ca428b0d96289.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/LightGrass1.png" +dest_files=["res://.godot/imported/LightGrass1.png-2fd346f92ed520cff72ca428b0d96289.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/hexmapper/assets/tiles/LightGrass2.png b/hexmapper/assets/tiles/LightGrass2.png new file mode 100644 index 0000000..4706893 Binary files /dev/null and b/hexmapper/assets/tiles/LightGrass2.png differ diff --git a/hexmapper/assets/tiles/LightGrass2.png.import b/hexmapper/assets/tiles/LightGrass2.png.import new file mode 100644 index 0000000..b0bed5e --- /dev/null +++ b/hexmapper/assets/tiles/LightGrass2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bbm1gpn388xih" +path="res://.godot/imported/LightGrass2.png-d42ccd2e27e0928e94e6fa36ee4dce09.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/LightGrass2.png" +dest_files=["res://.godot/imported/LightGrass2.png-d42ccd2e27e0928e94e6fa36ee4dce09.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/hexmapper/assets/tiles/LowHills1.png b/hexmapper/assets/tiles/LowHills1.png new file mode 100644 index 0000000..327867f Binary files /dev/null and b/hexmapper/assets/tiles/LowHills1.png differ diff --git a/hexmapper/assets/tiles/LowHills1.png.import b/hexmapper/assets/tiles/LowHills1.png.import new file mode 100644 index 0000000..1b2b8cf --- /dev/null +++ b/hexmapper/assets/tiles/LowHills1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dko5amaukdwcf" +path="res://.godot/imported/LowHills1.png-cf049dea6df2ec0c98ecee06224a3346.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/LowHills1.png" +dest_files=["res://.godot/imported/LowHills1.png-cf049dea6df2ec0c98ecee06224a3346.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/hexmapper/assets/tiles/LowHills2.png b/hexmapper/assets/tiles/LowHills2.png new file mode 100644 index 0000000..d5981f6 Binary files /dev/null and b/hexmapper/assets/tiles/LowHills2.png differ diff --git a/hexmapper/assets/tiles/LowHills2.png.import b/hexmapper/assets/tiles/LowHills2.png.import new file mode 100644 index 0000000..fd2f271 --- /dev/null +++ b/hexmapper/assets/tiles/LowHills2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://3sbagd2mxk6m" +path="res://.godot/imported/LowHills2.png-6cb74f9d7b3ded55e0814fbeea5ef02c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/LowHills2.png" +dest_files=["res://.godot/imported/LowHills2.png-6cb74f9d7b3ded55e0814fbeea5ef02c.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/hexmapper/assets/tiles/LowHills3.png b/hexmapper/assets/tiles/LowHills3.png new file mode 100644 index 0000000..855cc79 Binary files /dev/null and b/hexmapper/assets/tiles/LowHills3.png differ diff --git a/hexmapper/assets/tiles/LowHills3.png.import b/hexmapper/assets/tiles/LowHills3.png.import new file mode 100644 index 0000000..4c7223e --- /dev/null +++ b/hexmapper/assets/tiles/LowHills3.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://duewwfafrdy04" +path="res://.godot/imported/LowHills3.png-1bf9a200188cf11aa4c3cf7b5371c4a7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/LowHills3.png" +dest_files=["res://.godot/imported/LowHills3.png-1bf9a200188cf11aa4c3cf7b5371c4a7.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/hexmapper/assets/tiles/LowHills4.png b/hexmapper/assets/tiles/LowHills4.png new file mode 100644 index 0000000..e5a022b Binary files /dev/null and b/hexmapper/assets/tiles/LowHills4.png differ diff --git a/hexmapper/assets/tiles/LowHills4.png.import b/hexmapper/assets/tiles/LowHills4.png.import new file mode 100644 index 0000000..aae9b7e --- /dev/null +++ b/hexmapper/assets/tiles/LowHills4.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bp4kh51wjk7u6" +path="res://.godot/imported/LowHills4.png-577b29ccec7f13b2ea7d78becbd29503.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/LowHills4.png" +dest_files=["res://.godot/imported/LowHills4.png-577b29ccec7f13b2ea7d78becbd29503.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/hexmapper/assets/tiles/Mountains1.png b/hexmapper/assets/tiles/Mountains1.png new file mode 100644 index 0000000..a5675aa Binary files /dev/null and b/hexmapper/assets/tiles/Mountains1.png differ diff --git a/hexmapper/assets/tiles/Mountains1.png.import b/hexmapper/assets/tiles/Mountains1.png.import new file mode 100644 index 0000000..c1a9c4f --- /dev/null +++ b/hexmapper/assets/tiles/Mountains1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cqxw2wdptnrbf" +path="res://.godot/imported/Mountains1.png-51e03b184ce1782136445e71e6e577d8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Mountains1.png" +dest_files=["res://.godot/imported/Mountains1.png-51e03b184ce1782136445e71e6e577d8.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/hexmapper/assets/tiles/Mountains2.png b/hexmapper/assets/tiles/Mountains2.png new file mode 100644 index 0000000..8f6c01a Binary files /dev/null and b/hexmapper/assets/tiles/Mountains2.png differ diff --git a/hexmapper/assets/tiles/Mountains2.png.import b/hexmapper/assets/tiles/Mountains2.png.import new file mode 100644 index 0000000..0d60a73 --- /dev/null +++ b/hexmapper/assets/tiles/Mountains2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://lhfgjfm88fo0" +path="res://.godot/imported/Mountains2.png-7a742999a150db8ae39f35794b5aed35.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Mountains2.png" +dest_files=["res://.godot/imported/Mountains2.png-7a742999a150db8ae39f35794b5aed35.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/hexmapper/assets/tiles/Mountains5.png b/hexmapper/assets/tiles/Mountains5.png new file mode 100644 index 0000000..01a5859 Binary files /dev/null and b/hexmapper/assets/tiles/Mountains5.png differ diff --git a/hexmapper/assets/tiles/Mountains5.png.import b/hexmapper/assets/tiles/Mountains5.png.import new file mode 100644 index 0000000..2783ff1 --- /dev/null +++ b/hexmapper/assets/tiles/Mountains5.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c4r0lc06sguk4" +path="res://.godot/imported/Mountains5.png-f3f0ab0424ebe2e4ce68b33ae8374a24.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Mountains5.png" +dest_files=["res://.godot/imported/Mountains5.png-f3f0ab0424ebe2e4ce68b33ae8374a24.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/hexmapper/assets/tiles/Mud1.png b/hexmapper/assets/tiles/Mud1.png new file mode 100644 index 0000000..a48b89a Binary files /dev/null and b/hexmapper/assets/tiles/Mud1.png differ diff --git a/hexmapper/assets/tiles/Mud1.png.import b/hexmapper/assets/tiles/Mud1.png.import new file mode 100644 index 0000000..c5a1c93 --- /dev/null +++ b/hexmapper/assets/tiles/Mud1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cu61g6w2e4aoh" +path="res://.godot/imported/Mud1.png-0618d33a17818a33bc439b11a2714e25.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Mud1.png" +dest_files=["res://.godot/imported/Mud1.png-0618d33a17818a33bc439b11a2714e25.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/hexmapper/assets/tiles/Mud2.png b/hexmapper/assets/tiles/Mud2.png new file mode 100644 index 0000000..ae1d940 Binary files /dev/null and b/hexmapper/assets/tiles/Mud2.png differ diff --git a/hexmapper/assets/tiles/Mud2.png.import b/hexmapper/assets/tiles/Mud2.png.import new file mode 100644 index 0000000..a0d3e89 --- /dev/null +++ b/hexmapper/assets/tiles/Mud2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://jwg03781ugvv" +path="res://.godot/imported/Mud2.png-43e576fb7c7f4d771039f5b9903ffba5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Mud2.png" +dest_files=["res://.godot/imported/Mud2.png-43e576fb7c7f4d771039f5b9903ffba5.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/hexmapper/assets/tiles/Mud3.png b/hexmapper/assets/tiles/Mud3.png new file mode 100644 index 0000000..413b97b Binary files /dev/null and b/hexmapper/assets/tiles/Mud3.png differ diff --git a/hexmapper/assets/tiles/Mud3.png.import b/hexmapper/assets/tiles/Mud3.png.import new file mode 100644 index 0000000..1e98962 --- /dev/null +++ b/hexmapper/assets/tiles/Mud3.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://de0ojtfxy0hwk" +path="res://.godot/imported/Mud3.png-2ac8427eaaa35566e118f6e454e935cc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Mud3.png" +dest_files=["res://.godot/imported/Mud3.png-2ac8427eaaa35566e118f6e454e935cc.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/hexmapper/assets/tiles/Ocean1.png b/hexmapper/assets/tiles/Ocean1.png new file mode 100644 index 0000000..fa38481 Binary files /dev/null and b/hexmapper/assets/tiles/Ocean1.png differ diff --git a/hexmapper/assets/tiles/Ocean1.png.import b/hexmapper/assets/tiles/Ocean1.png.import new file mode 100644 index 0000000..0071a30 --- /dev/null +++ b/hexmapper/assets/tiles/Ocean1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cpq8ho4fjurm3" +path="res://.godot/imported/Ocean1.png-55ae717a099ec5e76bcc84dfb9a8251f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Ocean1.png" +dest_files=["res://.godot/imported/Ocean1.png-55ae717a099ec5e76bcc84dfb9a8251f.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/hexmapper/assets/tiles/Ocean2.png b/hexmapper/assets/tiles/Ocean2.png new file mode 100644 index 0000000..735cffa Binary files /dev/null and b/hexmapper/assets/tiles/Ocean2.png differ diff --git a/hexmapper/assets/tiles/Ocean2.png.import b/hexmapper/assets/tiles/Ocean2.png.import new file mode 100644 index 0000000..585c331 --- /dev/null +++ b/hexmapper/assets/tiles/Ocean2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dhbw2ufovgmij" +path="res://.godot/imported/Ocean2.png-f8ebb30e1a75231a1ff718c757adab7e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Ocean2.png" +dest_files=["res://.godot/imported/Ocean2.png-f8ebb30e1a75231a1ff718c757adab7e.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/hexmapper/assets/tiles/Orchards1.png b/hexmapper/assets/tiles/Orchards1.png new file mode 100644 index 0000000..7f2fdf9 Binary files /dev/null and b/hexmapper/assets/tiles/Orchards1.png differ diff --git a/hexmapper/assets/tiles/Orchards1.png.import b/hexmapper/assets/tiles/Orchards1.png.import new file mode 100644 index 0000000..75c211d --- /dev/null +++ b/hexmapper/assets/tiles/Orchards1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dohuopl8ucxg1" +path="res://.godot/imported/Orchards1.png-2112c9c710fc1b797598b4959ffd9fb2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Orchards1.png" +dest_files=["res://.godot/imported/Orchards1.png-2112c9c710fc1b797598b4959ffd9fb2.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/hexmapper/assets/tiles/Orchards2.png b/hexmapper/assets/tiles/Orchards2.png new file mode 100644 index 0000000..2832cb2 Binary files /dev/null and b/hexmapper/assets/tiles/Orchards2.png differ diff --git a/hexmapper/assets/tiles/Orchards2.png.import b/hexmapper/assets/tiles/Orchards2.png.import new file mode 100644 index 0000000..2b11d3f --- /dev/null +++ b/hexmapper/assets/tiles/Orchards2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cy34u648kgagy" +path="res://.godot/imported/Orchards2.png-f84615d90905d3340a585422f4294679.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Orchards2.png" +dest_files=["res://.godot/imported/Orchards2.png-f84615d90905d3340a585422f4294679.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/hexmapper/assets/tiles/Rough1.png b/hexmapper/assets/tiles/Rough1.png new file mode 100644 index 0000000..3b496ae Binary files /dev/null and b/hexmapper/assets/tiles/Rough1.png differ diff --git a/hexmapper/assets/tiles/Rough1.png.import b/hexmapper/assets/tiles/Rough1.png.import new file mode 100644 index 0000000..7992bbe --- /dev/null +++ b/hexmapper/assets/tiles/Rough1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://crd2nigesg44x" +path="res://.godot/imported/Rough1.png-c881f66ec55fc46db40213da34895bb3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Rough1.png" +dest_files=["res://.godot/imported/Rough1.png-c881f66ec55fc46db40213da34895bb3.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/hexmapper/assets/tiles/Rough2.png b/hexmapper/assets/tiles/Rough2.png new file mode 100644 index 0000000..e890a92 Binary files /dev/null and b/hexmapper/assets/tiles/Rough2.png differ diff --git a/hexmapper/assets/tiles/Rough2.png.import b/hexmapper/assets/tiles/Rough2.png.import new file mode 100644 index 0000000..a9bd376 --- /dev/null +++ b/hexmapper/assets/tiles/Rough2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bgkolct4kprum" +path="res://.godot/imported/Rough2.png-1f83b005888ae4406cbbbed7476fc7c1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Rough2.png" +dest_files=["res://.godot/imported/Rough2.png-1f83b005888ae4406cbbbed7476fc7c1.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/hexmapper/assets/tiles/SaltBush1.png b/hexmapper/assets/tiles/SaltBush1.png new file mode 100644 index 0000000..0f33f72 Binary files /dev/null and b/hexmapper/assets/tiles/SaltBush1.png differ diff --git a/hexmapper/assets/tiles/SaltBush1.png.import b/hexmapper/assets/tiles/SaltBush1.png.import new file mode 100644 index 0000000..3fd5737 --- /dev/null +++ b/hexmapper/assets/tiles/SaltBush1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://s8hyiyo38vlo" +path="res://.godot/imported/SaltBush1.png-57f03ffd3b81ccd381ee1b96414f4ab8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/SaltBush1.png" +dest_files=["res://.godot/imported/SaltBush1.png-57f03ffd3b81ccd381ee1b96414f4ab8.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/hexmapper/assets/tiles/SaltBush2.png b/hexmapper/assets/tiles/SaltBush2.png new file mode 100644 index 0000000..10fb6b7 Binary files /dev/null and b/hexmapper/assets/tiles/SaltBush2.png differ diff --git a/hexmapper/assets/tiles/SaltBush2.png.import b/hexmapper/assets/tiles/SaltBush2.png.import new file mode 100644 index 0000000..c2a7a72 --- /dev/null +++ b/hexmapper/assets/tiles/SaltBush2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cpcwusmk3phk6" +path="res://.godot/imported/SaltBush2.png-1385247f4058392cad84d00887df5f75.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/SaltBush2.png" +dest_files=["res://.godot/imported/SaltBush2.png-1385247f4058392cad84d00887df5f75.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/hexmapper/assets/tiles/Snow1.png b/hexmapper/assets/tiles/Snow1.png new file mode 100644 index 0000000..266f6cb Binary files /dev/null and b/hexmapper/assets/tiles/Snow1.png differ diff --git a/hexmapper/assets/tiles/Snow1.png.import b/hexmapper/assets/tiles/Snow1.png.import new file mode 100644 index 0000000..b18d829 --- /dev/null +++ b/hexmapper/assets/tiles/Snow1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dabilovm2tssi" +path="res://.godot/imported/Snow1.png-1a56f50e9b4b4d5444338c7fe5a253f6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Snow1.png" +dest_files=["res://.godot/imported/Snow1.png-1a56f50e9b4b4d5444338c7fe5a253f6.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/hexmapper/assets/tiles/Snow2.png b/hexmapper/assets/tiles/Snow2.png new file mode 100644 index 0000000..eafa449 Binary files /dev/null and b/hexmapper/assets/tiles/Snow2.png differ diff --git a/hexmapper/assets/tiles/Snow2.png.import b/hexmapper/assets/tiles/Snow2.png.import new file mode 100644 index 0000000..9413321 --- /dev/null +++ b/hexmapper/assets/tiles/Snow2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cpe7hud7qnxgx" +path="res://.godot/imported/Snow2.png-a26acb4fd2bc6f84c8fbdc37b8d244ef.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Snow2.png" +dest_files=["res://.godot/imported/Snow2.png-a26acb4fd2bc6f84c8fbdc37b8d244ef.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/hexmapper/assets/tiles/Water1.png b/hexmapper/assets/tiles/Water1.png new file mode 100644 index 0000000..27e23df Binary files /dev/null and b/hexmapper/assets/tiles/Water1.png differ diff --git a/hexmapper/assets/tiles/Water1.png.import b/hexmapper/assets/tiles/Water1.png.import new file mode 100644 index 0000000..b7c4e91 --- /dev/null +++ b/hexmapper/assets/tiles/Water1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bxhfb2mt8bjo3" +path="res://.godot/imported/Water1.png-4165410b5d69c0fb95ed5f3931607d77.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Water1.png" +dest_files=["res://.godot/imported/Water1.png-4165410b5d69c0fb95ed5f3931607d77.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/hexmapper/assets/tiles/Water2.png b/hexmapper/assets/tiles/Water2.png new file mode 100644 index 0000000..b3bc837 Binary files /dev/null and b/hexmapper/assets/tiles/Water2.png differ diff --git a/hexmapper/assets/tiles/Water2.png.import b/hexmapper/assets/tiles/Water2.png.import new file mode 100644 index 0000000..3689271 --- /dev/null +++ b/hexmapper/assets/tiles/Water2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cyvfvarinlerc" +path="res://.godot/imported/Water2.png-21f7093bd5164679bab371fb991fd0db.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Water2.png" +dest_files=["res://.godot/imported/Water2.png-21f7093bd5164679bab371fb991fd0db.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/hexmapper/assets/tiles/Woods1.png b/hexmapper/assets/tiles/Woods1.png new file mode 100644 index 0000000..d47cf95 Binary files /dev/null and b/hexmapper/assets/tiles/Woods1.png differ diff --git a/hexmapper/assets/tiles/Woods1.png.import b/hexmapper/assets/tiles/Woods1.png.import new file mode 100644 index 0000000..dc59930 --- /dev/null +++ b/hexmapper/assets/tiles/Woods1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://gtfqs81urbcc" +path="res://.godot/imported/Woods1.png-4299742b8f32747ec5538ce3e13b7ec1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Woods1.png" +dest_files=["res://.godot/imported/Woods1.png-4299742b8f32747ec5538ce3e13b7ec1.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/hexmapper/assets/tiles/Woods2.png b/hexmapper/assets/tiles/Woods2.png new file mode 100644 index 0000000..08b73b8 Binary files /dev/null and b/hexmapper/assets/tiles/Woods2.png differ diff --git a/hexmapper/assets/tiles/Woods2.png.import b/hexmapper/assets/tiles/Woods2.png.import new file mode 100644 index 0000000..ed7225d --- /dev/null +++ b/hexmapper/assets/tiles/Woods2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cv7gs0r7avhrn" +path="res://.godot/imported/Woods2.png-0ea1aa7c9499c9fb1bdfbb4c16e863f9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/Woods2.png" +dest_files=["res://.godot/imported/Woods2.png-0ea1aa7c9499c9fb1bdfbb4c16e863f9.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/hexmapper/assets/tiles/WoodsDark1.png b/hexmapper/assets/tiles/WoodsDark1.png new file mode 100644 index 0000000..b59dccf Binary files /dev/null and b/hexmapper/assets/tiles/WoodsDark1.png differ diff --git a/hexmapper/assets/tiles/WoodsDark1.png.import b/hexmapper/assets/tiles/WoodsDark1.png.import new file mode 100644 index 0000000..fb3d8c3 --- /dev/null +++ b/hexmapper/assets/tiles/WoodsDark1.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://57awx7wvxkbb" +path="res://.godot/imported/WoodsDark1.png-b5b5aeb5b8bc0b25d7a2f9a5b187930a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/WoodsDark1.png" +dest_files=["res://.godot/imported/WoodsDark1.png-b5b5aeb5b8bc0b25d7a2f9a5b187930a.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/hexmapper/assets/tiles/WoodsDark2.png b/hexmapper/assets/tiles/WoodsDark2.png new file mode 100644 index 0000000..37df45f Binary files /dev/null and b/hexmapper/assets/tiles/WoodsDark2.png differ diff --git a/hexmapper/assets/tiles/WoodsDark2.png.import b/hexmapper/assets/tiles/WoodsDark2.png.import new file mode 100644 index 0000000..0e61ece --- /dev/null +++ b/hexmapper/assets/tiles/WoodsDark2.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://nf3fvj67mt7b" +path="res://.godot/imported/WoodsDark2.png-ded0709c2060646e6605ce2e2475909a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/tiles/WoodsDark2.png" +dest_files=["res://.godot/imported/WoodsDark2.png-ded0709c2060646e6605ce2e2475909a.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/hexmapper/icon.svg b/hexmapper/icon.svg new file mode 100644 index 0000000..9d8b7fa --- /dev/null +++ b/hexmapper/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/hexmapper/icon.svg.import b/hexmapper/icon.svg.import new file mode 100644 index 0000000..a9f07b1 --- /dev/null +++ b/hexmapper/icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b3uaewgrvf85" +path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.svg" +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.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/hexmapper/project.godot b/hexmapper/project.godot new file mode 100644 index 0000000..9b850dc --- /dev/null +++ b/hexmapper/project.godot @@ -0,0 +1,40 @@ +; 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="HexMap_01_Alpha" +run/main_scene="uid://li0mfftily5e" +config/features=PackedStringArray("4.4", "GL Compatibility") +config/icon="res://icon.svg" + +[autoload] + +Global="*res://_autoload/global.gd" + +[display] + +window/size/viewport_width=1920 +window/size/viewport_height=1080 +window/stretch/mode="canvas_items" +window/stretch/aspect="expand" + +[editor_plugins] + +enabled=PackedStringArray("res://addons/script-ide/plugin.cfg") + +[gui] + +theme/custom="uid://cqh7512jkfhu3" + +[rendering] + +renderer/rendering_method="gl_compatibility" +renderer/rendering_method.mobile="gl_compatibility" diff --git a/hexmapper/resources/map_data.gd b/hexmapper/resources/map_data.gd new file mode 100644 index 0000000..91df244 --- /dev/null +++ b/hexmapper/resources/map_data.gd @@ -0,0 +1,4 @@ +class_name MapData +extends Resource + +@export var cells:Array[Vector2i] = [] diff --git a/hexmapper/resources/map_data.gd.uid b/hexmapper/resources/map_data.gd.uid new file mode 100644 index 0000000..ee203af --- /dev/null +++ b/hexmapper/resources/map_data.gd.uid @@ -0,0 +1 @@ +uid://b4c1jjsqmr4kn diff --git a/hexmapper/resources/settings.gd b/hexmapper/resources/settings.gd new file mode 100644 index 0000000..3276664 --- /dev/null +++ b/hexmapper/resources/settings.gd @@ -0,0 +1,5 @@ +class_name Settings +extends Resource + +@export var current_project_dir:String = "" +@export var current_map_name:String = "" diff --git a/hexmapper/resources/settings.gd.uid b/hexmapper/resources/settings.gd.uid new file mode 100644 index 0000000..de3a386 --- /dev/null +++ b/hexmapper/resources/settings.gd.uid @@ -0,0 +1 @@ +uid://dpwpbevirfufx diff --git a/hexmapper/scenes/MainMap/_MainMap.tscn b/hexmapper/scenes/MainMap/_MainMap.tscn new file mode 100644 index 0000000..864b19a --- /dev/null +++ b/hexmapper/scenes/MainMap/_MainMap.tscn @@ -0,0 +1,253 @@ +[gd_scene load_steps=19 format=4 uid="uid://li0mfftily5e"] + +[ext_resource type="Script" uid="uid://dnfabi8ksjvm2" path="res://scenes/MainMap/map_layer_logic.gd" id="1_74o3d"] +[ext_resource type="Script" uid="uid://rxaxc2114upf" path="res://scenes/MainMap/map_manager.gd" id="1_fax2j"] +[ext_resource type="Script" uid="uid://wvdosjbdlsjd" path="res://scenes/MainMap/btn_palette.gd" id="2_fax2j"] +[ext_resource type="Texture2D" uid="uid://cit5dnn6eoun1" path="res://assets/spritesheets/ui_72x72_spritesheet.png" id="3_gpn0d"] +[ext_resource type="Texture2D" uid="uid://bf0ux0t00blb7" path="res://assets/spritesheets/map_buildings_72x72_spritesheet.png" id="3_kyvod"] +[ext_resource type="Script" uid="uid://bcrhouavyrrm" path="res://scenes/MainMap/cursor_map_layer.gd" id="4_qib1m"] +[ext_resource type="Script" uid="uid://bqj8p0m6qt43k" path="res://scenes/MainMap/cursor_timer.gd" id="5_8wy1m"] +[ext_resource type="Script" uid="uid://1nbd6r3bgx6i" path="res://scenes/MainMap/resource_saver.gd" id="8_4uh5x"] +[ext_resource type="Script" uid="uid://b5v0k8cmkbrsr" path="res://scenes/MainMap/startup.gd" id="8_y3acc"] + +[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_cja8c"] +load_path = "res://.godot/imported/map_hex_terrain_spritesheet.png-44d6553f705cdcfc29c8dde51198c573.ctex" + +[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_v0x2j"] +texture = SubResource("CompressedTexture2D_cja8c") +separation = Vector2i(1, 1) +texture_region_size = Vector2i(72, 72) +0:0/0 = 0 +1:0/0 = 0 +2:0/0 = 0 +3:0/0 = 0 +4:0/0 = 0 +5:0/0 = 0 +6:0/0 = 0 +7:0/0 = 0 +0:1/0 = 0 +1:1/0 = 0 +2:1/0 = 0 +3:1/0 = 0 +4:1/0 = 0 +5:1/0 = 0 +6:1/0 = 0 +7:1/0 = 0 +0:2/0 = 0 +1:2/0 = 0 +2:2/0 = 0 +3:2/0 = 0 +4:2/0 = 0 +5:2/0 = 0 +6:2/0 = 0 +7:2/0 = 0 +0:3/0 = 0 +1:3/0 = 0 +2:3/0 = 0 +3:3/0 = 0 +4:3/0 = 0 +5:3/0 = 0 +6:3/0 = 0 +7:3/0 = 0 +0:4/0 = 0 +1:4/0 = 0 +2:4/0 = 0 +3:4/0 = 0 +4:4/0 = 0 +5:4/0 = 0 +6:4/0 = 0 +7:4/0 = 0 +0:5/0 = 0 +1:5/0 = 0 +2:5/0 = 0 +3:5/0 = 0 +4:5/0 = 0 +5:5/0 = 0 +6:5/0 = 0 +7:5/0 = 0 +0:6/0 = 0 +1:6/0 = 0 +2:6/0 = 0 +3:6/0 = 0 +4:6/0 = 0 +5:6/0 = 0 +6:6/0 = 0 +7:6/0 = 0 + +[sub_resource type="TileSet" id="TileSet_oxvhj"] +tile_shape = 3 +tile_layout = 5 +tile_offset_axis = 1 +tile_size = Vector2i(72, 72) +sources/0 = SubResource("TileSetAtlasSource_v0x2j") +tile_proxies/coords_level = [[0, Vector2i(0, 0)], [51, Vector2i(0, 0)], [1, Vector2i(0, 0)], [51, Vector2i(1, 0)], [2, Vector2i(0, 0)], [51, Vector2i(2, 0)], [3, Vector2i(0, 0)], [51, Vector2i(3, 0)], [4, Vector2i(0, 0)], [51, Vector2i(4, 0)], [5, Vector2i(0, 0)], [51, Vector2i(5, 0)], [6, Vector2i(0, 0)], [51, Vector2i(6, 0)], [7, Vector2i(0, 0)], [51, Vector2i(0, 1)], [8, Vector2i(0, 0)], [51, Vector2i(1, 1)], [9, Vector2i(0, 0)], [51, Vector2i(2, 1)], [10, Vector2i(0, 0)], [51, Vector2i(3, 1)], [11, Vector2i(0, 0)], [51, Vector2i(4, 1)], [12, Vector2i(0, 0)], [51, Vector2i(5, 1)], [13, Vector2i(0, 0)], [51, Vector2i(6, 1)], [14, Vector2i(0, 0)], [51, Vector2i(0, 2)], [15, Vector2i(0, 0)], [51, Vector2i(1, 2)], [16, Vector2i(0, 0)], [51, Vector2i(2, 2)], [17, Vector2i(0, 0)], [51, Vector2i(3, 2)], [18, Vector2i(0, 0)], [51, Vector2i(4, 2)], [19, Vector2i(0, 0)], [51, Vector2i(5, 2)], [20, Vector2i(0, 0)], [51, Vector2i(6, 2)], [21, Vector2i(0, 0)], [51, Vector2i(0, 3)], [22, Vector2i(0, 0)], [51, Vector2i(1, 3)], [23, Vector2i(0, 0)], [51, Vector2i(2, 3)], [24, Vector2i(0, 0)], [51, Vector2i(3, 3)], [25, Vector2i(0, 0)], [51, Vector2i(4, 3)], [26, Vector2i(0, 0)], [51, Vector2i(5, 3)], [27, Vector2i(0, 0)], [51, Vector2i(6, 3)], [28, Vector2i(0, 0)], [51, Vector2i(0, 4)], [29, Vector2i(0, 0)], [51, Vector2i(1, 4)], [30, Vector2i(0, 0)], [51, Vector2i(2, 4)], [31, Vector2i(0, 0)], [51, Vector2i(3, 4)], [32, Vector2i(0, 0)], [51, Vector2i(4, 4)], [33, Vector2i(0, 0)], [51, Vector2i(5, 4)], [34, Vector2i(0, 0)], [51, Vector2i(6, 4)], [35, Vector2i(0, 0)], [51, Vector2i(0, 5)], [36, Vector2i(0, 0)], [51, Vector2i(1, 5)], [37, Vector2i(0, 0)], [51, Vector2i(2, 5)], [38, Vector2i(0, 0)], [51, Vector2i(3, 5)], [39, Vector2i(0, 0)], [51, Vector2i(4, 5)], [40, Vector2i(0, 0)], [51, Vector2i(5, 5)], [41, Vector2i(0, 0)], [51, Vector2i(6, 5)], [42, Vector2i(0, 0)], [51, Vector2i(0, 6)], [43, Vector2i(0, 0)], [51, Vector2i(1, 6)], [44, Vector2i(0, 0)], [51, Vector2i(2, 6)], [45, Vector2i(0, 0)], [51, Vector2i(3, 6)], [46, Vector2i(0, 0)], [51, Vector2i(4, 6)], [47, Vector2i(0, 0)], [51, Vector2i(5, 6)], [48, Vector2i(0, 0)], [51, Vector2i(6, 6)], [49, Vector2i(0, 0)], [51, Vector2i(0, 7)], [50, Vector2i(0, 0)], [51, Vector2i(1, 7)]] + +[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_4uh5x"] +texture = ExtResource("3_kyvod") +texture_region_size = Vector2i(72, 72) +0:0/0 = 0 +1:0/0 = 0 + +[sub_resource type="TileSet" id="TileSet_y3acc"] +tile_shape = 3 +tile_layout = 5 +tile_offset_axis = 1 +tile_size = Vector2i(72, 72) +sources/1 = SubResource("TileSetAtlasSource_4uh5x") + +[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_qib1m"] +texture = ExtResource("3_gpn0d") +texture_region_size = Vector2i(72, 72) +0:0/0 = 0 + +[sub_resource type="TileSet" id="TileSet_fax2j"] +tile_shape = 3 +tile_layout = 5 +tile_offset_axis = 1 +tile_size = Vector2i(72, 72) +sources/1 = SubResource("TileSetAtlasSource_qib1m") + +[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_ioj5u"] +load_path = "res://.godot/imported/BoulderHills1.png-3ee92d43833962adc5c138e74c73b76b.ctex" + +[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_slrw0"] +load_path = "res://.godot/imported/Grass1.png-95db52ec56c98c7586df38eac38ccfca.ctex" + +[node name="Main" type="Control"] +layout_mode = 3 +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 + +[node name="Camera2D" type="Camera2D" parent="."] +anchor_mode = 0 +editor_draw_limits = true + +[node name="Map" type="Control" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_fax2j") + +[node name="GroundMapLayer" type="TileMapLayer" parent="Map"] +unique_name_in_owner = true +rotation = -0.00175348 +tile_map_data = PackedByteArray("AAD+////AAAFAAEAAAD/////AAAFAAEAAAAAAP//AAAEAAUAAAAAAAAAAAAFAAEAAAD//wAAAAAFAAEAAAD+/wEAAAAFAAMAAAD//wEAAAAFAAMAAAAAAAEAAAAFAAMAAAD+/wAAAAACAAIAAAD9////AAACAAIAAAD9/wAAAAACAAIAAAD9/wEAAAACAAIAAAD8/wAAAAACAAIAAAD8////AAACAAIAAAAEAAEAAAACAAAAAAAFAAEAAAACAAAAAAAGAAEAAAACAAAAAAAHAAEAAAACAAAAAAAHAAAAAAACAAAAAAAGAAAAAAACAAAAAAAFAAAAAAACAAAAAAAEAAAAAAACAAAAAAAHAAIAAAACAAAAAAAGAAIAAAACAAAAAAAFAAIAAAACAAAAAAAEAAIAAAACAAAAAAACAP3/AAAEAAUAAAADAP7/AAAEAAUAAAADAP3/AAAEAAUAAAACAP7/AAAEAAUAAAABAP3/AAAEAAUAAAABAPz/AAAEAAUAAAACAPz/AAAEAAUAAAALAAMAAAABAAEAAAALAAIAAAABAAEAAAALAAEAAAABAAEAAAALAAAAAAABAAEAAAAMAAAAAAABAAEAAAALAP//AAABAAEAAAAMAP//AAABAAEAAAAMAP7/AAABAAEAAAAMAAEAAAABAAEAAAAMAAIAAAABAAEAAAANAAMAAAABAAEAAAAMAAMAAAABAAEAAAANAAQAAAABAAEAAAAMAAQAAAABAAEAAAAMAAUAAAABAAEAAAANAAIAAAABAAEAAAAMAPb/AAABAAEAAAAMAPf/AAABAAEAAAAMAPj/AAABAAEAAAAMAPn/AAABAAEAAAAMAPr/AAABAAEAAAAMAPv/AAABAAEAAAAMAPz/AAABAAEAAAAMAP3/AAABAAEAAAANAPb/AAABAAEAAAANAPf/AAABAAEAAAANAPj/AAABAAEAAAANAPn/AAABAAEAAAANAPr/AAABAAEAAAANAPv/AAABAAEAAAANAPz/AAABAAEAAAANAP3/AAABAAEAAAANAP7/AAABAAEAAAAOAPb/AAABAAEAAAAOAPf/AAABAAEAAAAOAPj/AAABAAEAAAAOAPn/AAABAAEAAAAOAPr/AAABAAEAAAAOAPv/AAABAAEAAAAOAPz/AAABAAEAAAAOAP3/AAABAAEAAAAOAP7/AAABAAEAAAAPAPb/AAABAAEAAAAPAPf/AAABAAEAAAAPAPj/AAABAAEAAAAPAPn/AAABAAEAAAAPAPr/AAABAAEAAAAPAPv/AAABAAEAAAAPAPz/AAABAAEAAAAPAP3/AAABAAEAAAAPAP7/AAABAAEAAAAQAPb/AAABAAEAAAAQAPf/AAABAAEAAAAQAPj/AAABAAEAAAAQAPn/AAABAAEAAAAQAPr/AAABAAEAAAAQAPv/AAABAAEAAAAQAPz/AAABAAEAAAAQAP3/AAABAAEAAAAQAP7/AAABAAEAAAARAPb/AAABAAEAAAARAPf/AAABAAEAAAARAPj/AAABAAEAAAARAPn/AAABAAEAAAARAPr/AAABAAEAAAARAPv/AAABAAEAAAARAPz/AAABAAEAAAARAP3/AAABAAEAAAARAP7/AAABAAEAAAASAPb/AAABAAEAAAASAPf/AAABAAEAAAASAPj/AAABAAEAAAASAPn/AAABAAEAAAASAPr/AAABAAEAAAASAPv/AAABAAEAAAASAPz/AAABAAEAAAASAP3/AAABAAEAAAASAP7/AAABAAEAAAATAPb/AAABAAEAAAATAPf/AAABAAEAAAATAPj/AAABAAEAAAATAPn/AAABAAEAAAATAPr/AAABAAEAAAATAPv/AAABAAEAAAATAPz/AAABAAEAAAATAP3/AAABAAEAAAATAP7/AAABAAEAAAAUAPb/AAABAAEAAAAUAPf/AAABAAEAAAAUAPj/AAABAAEAAAAUAPn/AAABAAEAAAAUAPr/AAABAAEAAAAUAPv/AAABAAEAAAAUAPz/AAABAAEAAAAUAP3/AAABAAEAAAAUAP7/AAABAAEAAAAVAPb/AAABAAEAAAAVAPf/AAABAAEAAAAVAPj/AAABAAEAAAAVAPn/AAABAAEAAAAVAPr/AAABAAEAAAAVAPv/AAABAAEAAAAVAPz/AAABAAEAAAAVAP3/AAABAAEAAAAVAP7/AAABAAEAAAAFAPb/AAAAAAMAAAAFAPf/AAAAAAMAAAAGAPb/AAAAAAMAAAAGAPf/AAAAAAMAAAAHAPb/AAAAAAMAAAAHAPf/AAAAAAMAAAAIAPb/AAAAAAMAAAAIAPf/AAAAAAMAAAAJAPb/AAAAAAMAAAAJAPf/AAAAAAMAAAAKAPb/AAAAAAMAAAAKAPf/AAAAAAMAAAALAPb/AAAAAAMAAAALAPf/AAAAAAMAAAAPAPH/AAABAAEAAAAPAPL/AAABAAEAAAAPAPP/AAABAAEAAAAPAPT/AAABAAEAAAAPAPX/AAABAAEAAAAQAPH/AAABAAEAAAAQAPL/AAABAAEAAAAQAPP/AAABAAEAAAAQAPT/AAABAAEAAAAQAPX/AAABAAEAAAARAPH/AAABAAEAAAARAPL/AAABAAEAAAARAPP/AAABAAEAAAARAPT/AAABAAEAAAARAPX/AAABAAEAAAAJAPr/AAABAAEAAAAJAPv/AAABAAEAAAAJAPz/AAAAAAMAAAAKAPr/AAABAAEAAAAKAPv/AAABAAEAAAAKAPz/AAAAAAMAAAALAPr/AAABAAEAAAALAPv/AAABAAEAAAALAPz/AAAAAAMAAAABAAIAAAAFAAMAAAAAAAIAAAAFAAMAAAD//wIAAAAFAAMAAAD+/wIAAAAFAAMAAAD9/wIAAAAEAAAAAAD+/wMAAAAEAAAAAAD//wMAAAAEAAAAAAAAAAMAAAAEAAAAAAABAAMAAAAEAAAAAAACAAMAAAAEAAAAAAACAAIAAAAEAAAAAAABAAEAAAAEAAAAAAABAAAAAAAEAAAAAAABAP//AAAEAAAAAAACAAAAAAAEAAAAAAACAP//AAAEAAAAAAADAAEAAAAEAAAAAAACAAEAAAAEAAAAAAD+//7/AAAEAAUAAAD///7/AAAEAAUAAAAAAP7/AAAEAAUAAAAAAP3/AAAEAAUAAAACAPv/AAAEAAUAAAAAAPz/AAAEAAUAAAABAP7/AAAEAAUAAAADAAAAAAAEAAUAAAADAP//AAAEAAUAAAAEAP//AAAEAAUAAAAEAP7/AAAEAAUAAAAFAP7/AAAEAAUAAAADAAIAAAAEAAUAAAADAAMAAAAEAAUAAAADAAQAAAABAAQAAAACAAQAAAABAAQAAAACAAUAAAABAAQAAAABAAQAAAABAAQAAAADAAUAAAABAAQAAAAEAAQAAAACAAAAAAABAAUAAAABAAQAAAAAAAUAAAABAAQAAAD//wUAAAABAAQAAAD+/wUAAAABAAQAAAD//wQAAAABAAQAAAAAAAQAAAABAAQAAAD+/wQAAAABAAQAAAAIAAEAAAACAAAAAAAIAAIAAAACAAAAAAAIAAMAAAACAAAAAAAHAAMAAAACAAAAAAAHAAQAAAACAAAAAAAHAAUAAAACAAAAAAAGAAMAAAACAAAAAAAFAAMAAAACAAAAAAAFAAQAAAACAAAAAAAEAAMAAAACAAAAAAAIAAQAAAACAAAAAAAIAAAAAAACAAAAAAAJAAEAAAACAAAAAAAJAAIAAAACAAAAAAAJAAMAAAACAAAAAAAIAAUAAAACAAAAAAAIAP//AAACAAAAAAALAPn/AAABAAEAAAAKAP3/AAAAAAMAAAALAP7/AAAAAAMAAAANAAAAAAABAAEAAAAOAAAAAAABAAEAAAAOAP//AAABAAEAAAAPAP//AAABAAEAAAATAPX/AAABAAEAAAASAPT/AAABAAEAAAAKAPj/AAAAAAMAAAAJAPj/AAAAAAMAAAAKAPn/AAABAAEAAAAJAPn/AAABAAEAAAAIAPr/AAABAAEAAAASAPX/AAABAAEAAAALAPj/AAABAAEAAAALAP3/AAAAAAMAAAANAP//AAABAAEAAAD8/wMAAAABAAAAAAD8/wIAAAABAAAAAAD9/wMAAAABAAAAAAD9/wQAAAADAAAAAAD8/wQAAAADAAAAAAD9/wUAAAADAAAAAAD8/wUAAAAHAAIAAAD7/wQAAAAFAAEAAAD7/wUAAAAFAAEAAAD8/wYAAAAFAAEAAAD9/wYAAAAFAAEAAAD7/wYAAAAGAAIAAAD6/wUAAAAGAAIAAAD6/wYAAAAGAAIAAAA=") +tile_set = SubResource("TileSet_oxvhj") +script = ExtResource("1_74o3d") + +[node name="BuildingMapLayer" type="TileMapLayer" parent="Map"] +rotation = -0.00350696 +tile_map_data = PackedByteArray("AAD+////AAAFAAEAAAD/////AAAFAAEAAAAAAP//AAAEAAUAAAAAAAAAAAAFAAEAAAD//wAAAAAFAAEAAAD+/wEAAAAFAAMAAAD//wEAAAAFAAMAAAAAAAEAAAAFAAMAAAD+/wAAAQABAAAAAAD9////AAACAAIAAAD9/wAAAAACAAIAAAD9/wEAAAACAAIAAAD8/wAAAAACAAIAAAD8////AAACAAIAAAAEAAEAAAACAAAAAAAFAAEAAAACAAAAAAAGAAEAAAACAAAAAAAHAAEAAAACAAAAAAAHAAAAAAACAAAAAAAGAAAAAAACAAAAAAAFAAAAAAACAAAAAAAEAAAAAAACAAAAAAAHAAIAAAACAAAAAAAGAAIAAAACAAAAAAAFAAIAAAACAAAAAAAEAAIAAAACAAAAAAACAP3/AAAEAAUAAAADAP7/AAAEAAUAAAADAP3/AAAEAAUAAAACAP7/AAAEAAUAAAABAP3/AAAEAAUAAAABAPz/AAAEAAUAAAACAPz/AAAEAAUAAAALAAMAAAABAAEAAAALAAIAAAABAAEAAAALAAEAAAABAAEAAAALAAAAAAABAAEAAAAMAAAAAAABAAEAAAALAP//AAABAAEAAAAMAP//AAABAAEAAAAMAP7/AAABAAEAAAAMAAEAAAABAAEAAAAMAAIAAAABAAEAAAANAAMAAAABAAEAAAAMAAMAAAABAAEAAAANAAQAAAABAAEAAAAMAAQAAAABAAEAAAAMAAUAAAABAAEAAAANAAIAAAABAAEAAAAMAPb/AAABAAEAAAAMAPf/AAABAAEAAAAMAPj/AAABAAEAAAAMAPn/AAABAAEAAAAMAPr/AAABAAEAAAAMAPv/AAABAAEAAAAMAPz/AAABAAEAAAAMAP3/AAABAAEAAAANAPb/AAABAAEAAAANAPf/AAABAAEAAAANAPj/AAABAAEAAAANAPn/AAABAAEAAAANAPr/AAABAAEAAAANAPv/AAABAAEAAAANAPz/AAABAAEAAAANAP3/AAABAAEAAAANAP7/AAABAAEAAAAOAPb/AAABAAEAAAAOAPf/AAABAAEAAAAOAPj/AAABAAEAAAAOAPn/AAABAAEAAAAOAPr/AAABAAEAAAAOAPv/AAABAAEAAAAOAPz/AAABAAEAAAAOAP3/AAABAAEAAAAOAP7/AAABAAEAAAAPAPb/AAABAAEAAAAPAPf/AAABAAEAAAAPAPj/AAABAAEAAAAPAPn/AAABAAEAAAAPAPr/AAABAAEAAAAPAPv/AAABAAEAAAAPAPz/AAABAAEAAAAPAP3/AAABAAEAAAAPAP7/AAABAAEAAAAQAPb/AAABAAEAAAAQAPf/AAABAAEAAAAQAPj/AAABAAEAAAAQAPn/AAABAAEAAAAQAPr/AAABAAEAAAAQAPv/AAABAAEAAAAQAPz/AAABAAEAAAAQAP3/AAABAAEAAAAQAP7/AAABAAEAAAARAPb/AAABAAEAAAARAPf/AAABAAEAAAARAPj/AAABAAEAAAARAPn/AAABAAEAAAARAPr/AAABAAEAAAARAPv/AAABAAEAAAARAPz/AAABAAEAAAARAP3/AAABAAEAAAARAP7/AAABAAEAAAASAPb/AAABAAEAAAASAPf/AAABAAEAAAASAPj/AAABAAEAAAASAPn/AAABAAEAAAASAPr/AAABAAEAAAASAPv/AAABAAEAAAASAPz/AAABAAEAAAASAP3/AAABAAEAAAASAP7/AAABAAEAAAATAPb/AAABAAEAAAATAPf/AAABAAEAAAATAPj/AAABAAEAAAATAPn/AAABAAEAAAATAPr/AAABAAEAAAATAPv/AAABAAEAAAATAPz/AAABAAEAAAATAP3/AAABAAEAAAATAP7/AAABAAEAAAAUAPb/AAABAAEAAAAUAPf/AAABAAEAAAAUAPj/AAABAAEAAAAUAPn/AAABAAEAAAAUAPr/AAABAAEAAAAUAPv/AAABAAEAAAAUAPz/AAABAAEAAAAUAP3/AAABAAEAAAAUAP7/AAABAAEAAAAVAPb/AAABAAEAAAAVAPf/AAABAAEAAAAVAPj/AAABAAEAAAAVAPn/AAABAAEAAAAVAPr/AAABAAEAAAAVAPv/AAABAAEAAAAVAPz/AAABAAEAAAAVAP3/AAABAAEAAAAVAP7/AAABAAEAAAAFAPb/AAAAAAMAAAAFAPf/AAAAAAMAAAAGAPb/AAAAAAMAAAAGAPf/AAAAAAMAAAAHAPb/AAAAAAMAAAAHAPf/AAAAAAMAAAAIAPb/AAAAAAMAAAAIAPf/AAAAAAMAAAAJAPb/AAAAAAMAAAAJAPf/AAAAAAMAAAAKAPb/AAAAAAMAAAAKAPf/AAAAAAMAAAALAPb/AAAAAAMAAAALAPf/AAAAAAMAAAAPAPH/AAABAAEAAAAPAPL/AAABAAEAAAAPAPP/AAABAAEAAAAPAPT/AAABAAEAAAAPAPX/AAABAAEAAAAQAPH/AAABAAEAAAAQAPL/AAABAAEAAAAQAPP/AAABAAEAAAAQAPT/AAABAAEAAAAQAPX/AAABAAEAAAARAPH/AAABAAEAAAARAPL/AAABAAEAAAARAPP/AAABAAEAAAARAPT/AAABAAEAAAARAPX/AAABAAEAAAAJAPr/AAABAAEAAAAJAPv/AAABAAEAAAAJAPz/AAAAAAMAAAAKAPr/AAABAAEAAAAKAPv/AAABAAEAAAAKAPz/AAAAAAMAAAALAPr/AAABAAEAAAALAPv/AAABAAEAAAALAPz/AAAAAAMAAAABAAIAAAAFAAMAAAAAAAIAAAAFAAMAAAD//wIAAAAFAAMAAAD+/wIAAAAFAAMAAAD9/wIAAAAEAAAAAAD+/wMAAAAEAAAAAAD//wMAAAAEAAAAAAAAAAMAAAAEAAAAAAABAAMAAAAEAAAAAAACAAMAAAAEAAAAAAACAAIAAAAEAAAAAAABAAEAAAAEAAAAAAABAAAAAAAEAAAAAAABAP//AAAEAAAAAAACAAAAAAAEAAAAAAACAP//AAAEAAAAAAADAAEAAAAEAAAAAAACAAEAAAAEAAAAAAD+//7/AAAEAAUAAAD///7/AAAEAAUAAAAAAP7/AAAEAAUAAAAAAP3/AAAEAAUAAAACAPv/AAAEAAUAAAAAAPz/AAAEAAUAAAABAP7/AAAEAAUAAAADAAAAAAAEAAUAAAADAP//AAAEAAUAAAAEAP//AAAEAAUAAAAEAP7/AAAEAAUAAAAFAP7/AAAEAAUAAAADAAIAAAAEAAUAAAADAAMAAAAEAAUAAAADAAQAAAABAAQAAAACAAQAAAABAAQAAAACAAUAAAABAAQAAAABAAQAAAABAAQAAAADAAUAAAABAAQAAAAEAAQAAAACAAAAAAABAAUAAAABAAQAAAAAAAUAAAABAAQAAAD//wUAAAABAAQAAAD+/wUAAAABAAQAAAD//wQAAAABAAQAAAAAAAQAAAABAAQAAAD+/wQAAAABAAQAAAAIAAEAAAACAAAAAAAIAAIAAAACAAAAAAAIAAMAAAACAAAAAAAHAAMAAAACAAAAAAAHAAQAAAACAAAAAAAHAAUAAAACAAAAAAAGAAMAAAACAAAAAAAFAAMAAAACAAAAAAAFAAQAAAACAAAAAAAEAAMAAAACAAAAAAAIAAQAAAACAAAAAAAIAAAAAAACAAAAAAAJAAEAAAACAAAAAAAJAAIAAAACAAAAAAAJAAMAAAACAAAAAAAIAAUAAAACAAAAAAAIAP//AAACAAAAAAALAPn/AAABAAEAAAAKAP3/AAAAAAMAAAALAP7/AAAAAAMAAAANAAAAAAABAAEAAAAOAAAAAAABAAEAAAAOAP//AAABAAEAAAAPAP//AAABAAEAAAATAPX/AAABAAEAAAASAPT/AAABAAEAAAAKAPj/AAAAAAMAAAAJAPj/AAAAAAMAAAAKAPn/AAABAAEAAAAJAPn/AAABAAEAAAAIAPr/AAABAAEAAAASAPX/AAABAAEAAAALAPj/AAABAAEAAAALAP3/AAAAAAMAAAANAP//AAABAAEAAAD8/wMAAAABAAAAAAD8/wIAAAABAAAAAAD9/wMAAAABAAAAAAD9/wQAAAADAAAAAAD8/wQAAAADAAAAAAD9/wUAAAADAAAAAAD8/wUAAAAHAAIAAAD7/wQAAAAFAAEAAAD7/wUAAAAFAAEAAAD8/wYAAAAFAAEAAAD9/wYAAAAFAAEAAAD7/wYAAAAGAAIAAAD6/wUAAAAGAAIAAAD6/wYAAAAGAAIAAAA=") +tile_set = SubResource("TileSet_y3acc") + +[node name="CursorMapLayer" type="TileMapLayer" parent="Map"] +tile_set = SubResource("TileSet_fax2j") +script = ExtResource("4_qib1m") + +[node name="CursorTimer" type="Timer" parent="Map"] +unique_name_in_owner = true +script = ExtResource("5_8wy1m") + +[node name="CanvasLayer" type="CanvasLayer" parent="."] + +[node name="Palette" type="PanelContainer" parent="CanvasLayer"] +clip_contents = true +custom_minimum_size = Vector2(80, 80) +anchors_preset = 1 +anchor_left = 1.0 +anchor_right = 1.0 +offset_left = -80.0 +offset_bottom = 640.0 +grow_horizontal = 0 + +[node name="ScrollContainer" type="ScrollContainer" parent="CanvasLayer/Palette"] +layout_mode = 2 +follow_focus = true +draw_focus_border = true + +[node name="MarginContainer" type="MarginContainer" parent="CanvasLayer/Palette/ScrollContainer"] +layout_mode = 2 +size_flags_vertical = 3 +theme_override_constants/margin_left = 4 +theme_override_constants/margin_top = 2 +theme_override_constants/margin_right = 5 +theme_override_constants/margin_bottom = 2 + +[node name="PaletteContainer" type="VBoxContainer" parent="CanvasLayer/Palette/ScrollContainer/MarginContainer"] +unique_name_in_owner = true +clip_contents = true +custom_minimum_size = Vector2(72, 72) +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Label" type="Label" parent="CanvasLayer/Palette/ScrollContainer/MarginContainer/PaletteContainer"] +layout_mode = 2 +text = "Palette" +horizontal_alignment = 1 + +[node name="TextureRect" type="TextureRect" parent="CanvasLayer/Palette/ScrollContainer/MarginContainer/PaletteContainer"] +layout_mode = 2 +mouse_default_cursor_shape = 2 +texture = SubResource("CompressedTexture2D_ioj5u") + +[node name="TextureRect2" type="TextureRect" parent="CanvasLayer/Palette/ScrollContainer/MarginContainer/PaletteContainer"] +layout_mode = 2 +mouse_default_cursor_shape = 2 +texture = SubResource("CompressedTexture2D_slrw0") + +[node name="MenuTop" type="HBoxContainer" parent="CanvasLayer"] +offset_right = 227.0 +offset_bottom = 40.0 +size_flags_horizontal = 0 +size_flags_vertical = 0 + +[node name="opt_map" type="OptionButton" parent="CanvasLayer/MenuTop"] +layout_mode = 2 +selected = 0 +item_count = 4 +popup/item_0/text = "Karte..." +popup/item_0/id = 3 +popup/item_1/text = "...laden" +popup/item_1/id = 0 +popup/item_2/text = "...speichern" +popup/item_2/id = 1 +popup/item_3/text = "...speichern als..." +popup/item_3/id = 2 + +[node name="btn_palette" type="Button" parent="CanvasLayer/MenuTop"] +layout_mode = 2 +text = "Palette" +script = ExtResource("2_fax2j") + +[node name="Dialogs" type="Node2D" parent="CanvasLayer"] + +[node name="FileDialog" type="FileDialog" parent="CanvasLayer/Dialogs"] +unique_name_in_owner = true + +[node name="Data" type="Node" parent="."] + +[node name="ResourceSaver" type="Node" parent="Data"] +unique_name_in_owner = true +script = ExtResource("8_4uh5x") + +[node name="Logic" type="Node" parent="."] + +[node name="Startup" type="Node" parent="Logic"] +script = ExtResource("8_y3acc") + +[connection signal="mouse_entered" from="CanvasLayer/Palette" to="Map/CursorTimer" method="disable_cursor"] +[connection signal="mouse_exited" from="CanvasLayer/Palette" to="Map/CursorTimer" method="enable_cursor"] +[connection signal="mouse_entered" from="CanvasLayer/MenuTop" to="Map/CursorTimer" method="disable_cursor"] +[connection signal="mouse_exited" from="CanvasLayer/MenuTop" to="Map/CursorTimer" method="enable_cursor"] +[connection signal="mouse_entered" from="CanvasLayer/MenuTop/opt_map" to="Map/CursorTimer" method="disable_cursor"] +[connection signal="mouse_exited" from="CanvasLayer/MenuTop/opt_map" to="Map/CursorTimer" method="enable_cursor"] +[connection signal="selected_map_for_loading" from="Logic/Startup" to="Data/ResourceSaver" method="loadMap"] diff --git a/hexmapper/scenes/MainMap/btn_palette.gd b/hexmapper/scenes/MainMap/btn_palette.gd new file mode 100644 index 0000000..448667d --- /dev/null +++ b/hexmapper/scenes/MainMap/btn_palette.gd @@ -0,0 +1,5 @@ +extends Button + +func _gui_input(event): + if event is InputEventMouseButton and event.pressed: + print("Palette UI toggled") diff --git a/hexmapper/scenes/MainMap/btn_palette.gd.uid b/hexmapper/scenes/MainMap/btn_palette.gd.uid new file mode 100644 index 0000000..b7eca12 --- /dev/null +++ b/hexmapper/scenes/MainMap/btn_palette.gd.uid @@ -0,0 +1 @@ +uid://wvdosjbdlsjd diff --git a/hexmapper/scenes/MainMap/cursor_map_layer.gd b/hexmapper/scenes/MainMap/cursor_map_layer.gd new file mode 100644 index 0000000..902abcb --- /dev/null +++ b/hexmapper/scenes/MainMap/cursor_map_layer.gd @@ -0,0 +1,5 @@ +extends TileMapLayer + +func _unhandled_input(event): + if event is InputEventMouseButton: + print("A click reached the ui layer") diff --git a/hexmapper/scenes/MainMap/cursor_map_layer.gd.uid b/hexmapper/scenes/MainMap/cursor_map_layer.gd.uid new file mode 100644 index 0000000..cf4e280 --- /dev/null +++ b/hexmapper/scenes/MainMap/cursor_map_layer.gd.uid @@ -0,0 +1 @@ +uid://bcrhouavyrrm diff --git a/hexmapper/scenes/MainMap/cursor_timer.gd b/hexmapper/scenes/MainMap/cursor_timer.gd new file mode 100644 index 0000000..7efc64a --- /dev/null +++ b/hexmapper/scenes/MainMap/cursor_timer.gd @@ -0,0 +1,39 @@ +extends Timer + +@onready var cursor_timer: Timer = $"." +@onready var cursor_map_layer: TileMapLayer = $"../CursorMapLayer" + +var last_cursor_pos:Vector2i = Vector2i(0,0) +const atlas_source_id:int = 1 +var is_enabled:bool = true + +func _ready(): + cursor_timer.wait_time = 0.1 + cursor_timer.autostart = true + cursor_timer.one_shot = false + cursor_timer.timeout.connect(_on_tick) + +func _on_tick(): + if not is_enabled: return + + var mouse_pos = cursor_map_layer.get_local_mouse_position() + var cell_pos = cursor_map_layer.local_to_map(mouse_pos) + + if cell_pos == last_cursor_pos: return + + var atlas_coords = cursor_map_layer.get_cell_atlas_coords(cell_pos) + #print("Atlas:",atlas_coords) + + cursor_map_layer.set_cell(last_cursor_pos, -1) # Erase cursor + + var source_id = cursor_map_layer.get_cell_source_id(cell_pos) + #print("Source id=", source_id) + cursor_map_layer.set_cell(cell_pos, atlas_source_id, Vector2i(0,0)) # Set cursor + last_cursor_pos = cell_pos + +func disable_cursor() -> void: + cursor_map_layer.set_cell(last_cursor_pos, -1) # Erase cursor + is_enabled = false + +func enable_cursor() -> void: + is_enabled = true diff --git a/hexmapper/scenes/MainMap/cursor_timer.gd.uid b/hexmapper/scenes/MainMap/cursor_timer.gd.uid new file mode 100644 index 0000000..a755230 --- /dev/null +++ b/hexmapper/scenes/MainMap/cursor_timer.gd.uid @@ -0,0 +1 @@ +uid://bqj8p0m6qt43k diff --git a/hexmapper/scenes/MainMap/map_layer_logic.gd b/hexmapper/scenes/MainMap/map_layer_logic.gd new file mode 100644 index 0000000..db5a9aa --- /dev/null +++ b/hexmapper/scenes/MainMap/map_layer_logic.gd @@ -0,0 +1,24 @@ +extends TileMapLayer + +signal hex_clicked(cell_pos:Vector2, atlas_coords:Vector2) + +func _unhandled_input(event): + if event is InputEventMouseButton: + if event.pressed==false: return + + var mouse_pos = get_local_mouse_position() + var cell_pos = local_to_map(mouse_pos) + + var source_id = get_cell_source_id(cell_pos) + + if source_id > -1: + var atlas_coords = get_cell_atlas_coords(cell_pos) + hex_clicked.emit(cell_pos, atlas_coords) + + #Example: Place/erase tile on click + if event.button_index == MOUSE_BUTTON_LEFT: + #pass + #set_cell(cell_pos, 51, Vector2i(6, 1)) # Place tile + set_cell(cell_pos, 0, Vector2i(1, 2)) # Place tile + elif event.button_index == MOUSE_BUTTON_RIGHT: + set_cell(cell_pos, -1) # Erase tile diff --git a/hexmapper/scenes/MainMap/map_layer_logic.gd.uid b/hexmapper/scenes/MainMap/map_layer_logic.gd.uid new file mode 100644 index 0000000..f2d339c --- /dev/null +++ b/hexmapper/scenes/MainMap/map_layer_logic.gd.uid @@ -0,0 +1 @@ +uid://dnfabi8ksjvm2 diff --git a/hexmapper/scenes/MainMap/map_manager.gd b/hexmapper/scenes/MainMap/map_manager.gd new file mode 100644 index 0000000..bcd9e5b --- /dev/null +++ b/hexmapper/scenes/MainMap/map_manager.gd @@ -0,0 +1,80 @@ +extends Control + +@onready var palette: VBoxContainer = %PaletteContainer +@onready var map_layer = %GroundMapLayer +var content = null +var coord2tilename = {} +var tilename2coord = {} + +func _ready(): + load_csv() + map_layer.hex_clicked.connect(_on_hex_clicked) + + print("Palette initialized.") + + var atlas_texture = AtlasTexture.new() + var atlas_image = Image.new() + + atlas_image.load("res://assets/spritesheets/map_hex_terrain_72x72_spritesheet.png") + atlas_texture.atlas = ImageTexture.create_from_image(atlas_image) + atlas_texture.region = Rect2(Vector2(0,73),Vector2(72,72)) # x,y,width,height + + var tr = TextureRect.new() + tr.texture = atlas_texture + + palette.add_child(tr) + +func load_csv(): + var file = FileAccess.open("res://assets/spritesheets/map_hex_terrain_72x72_mapping.txt", FileAccess.READ) + content = file.get_as_text().strip_edges() + for line in content.split("\n"): + var l = line.split(",") + var x = int(l[0]) + var y = int(l[1]) + var tilename = l[2] + coord2tilename[ Vector2i(x,y) ] = tilename + tilename2coord[ tilename ] = Vector2i(x,y) + + +func _on_hex_clicked(cell_coord:Vector2, atlas_coords:Vector2): + print("A hex was clicked:", cell_coord, atlas_coords) + if atlas_coords in coord2tilename: + print(coord2tilename[atlas_coords]) + else: + print("Not found in spritesheet") + + + + +@onready var tile_palettes = { + "Terrain": { + "atlas_id":0, + "tiles":{ + "Grass1":"Gras", + "LowHills2":"Hügel", + "Woods1":"Wald" + } + }, + "Gebäude": { + "atlas_id":1, + "tiles":{ + "Church5":"Kirche" + } + } +} + +# get all tiles for 1 palette +func get_tiles(palette:String) -> Array: + var ret_array = [] + + for palette_name in tile_palettes.keys(): + if palette_name == palette: + for tile_key in tile_palettes[palette_name].tiles.keys(): + var tile_name = tile_palettes[palette_name].tiles[tile_key] + ret_array.append([tile_key, tile_name]) + + return ret_array + +func get_tile_texcoord(palette:String, tile_name:String) -> Vector2i: + var ret_v2 = Vector2(0,0) + return ret_v2 diff --git a/hexmapper/scenes/MainMap/map_manager.gd.uid b/hexmapper/scenes/MainMap/map_manager.gd.uid new file mode 100644 index 0000000..ad04519 --- /dev/null +++ b/hexmapper/scenes/MainMap/map_manager.gd.uid @@ -0,0 +1 @@ +uid://rxaxc2114upf diff --git a/hexmapper/scenes/MainMap/resource_saver.gd b/hexmapper/scenes/MainMap/resource_saver.gd new file mode 100644 index 0000000..7dcb86d --- /dev/null +++ b/hexmapper/scenes/MainMap/resource_saver.gd @@ -0,0 +1,24 @@ +extends Node + +# TODO: Sollte nur über Signal laden oder speichern + +func _ready(): + pass + +func saveMap(): + var map_data = MapData.new() + map_data.cells = %GroundMapLayer.get_used_cells() + var map_file = Global.settings["current_project_dir"] + "/" + Global.settings["current_map_name"] + ResourceSaver.save(map_data, map_file) + print("Saved {0}".format([map_file])) + +func loadMap(map_file_name): + # TODO: Clear TilemapLayers before loading + print("loadMap: {0}".format([map_file_name])) + var map:MapData = load(map_file_name) + + # TODO: Set TileMapLayer cells according to loaded info + for cell in map.cells: + #%GroundMapLayer.get_used_cells() = map.cells + print(cell) + diff --git a/hexmapper/scenes/MainMap/resource_saver.gd.uid b/hexmapper/scenes/MainMap/resource_saver.gd.uid new file mode 100644 index 0000000..bb0afc1 --- /dev/null +++ b/hexmapper/scenes/MainMap/resource_saver.gd.uid @@ -0,0 +1 @@ +uid://1nbd6r3bgx6i diff --git a/hexmapper/scenes/MainMap/startup.gd b/hexmapper/scenes/MainMap/startup.gd new file mode 100644 index 0000000..1d2497f --- /dev/null +++ b/hexmapper/scenes/MainMap/startup.gd @@ -0,0 +1,77 @@ +extends Node + +signal selected_map_for_loading(map_file_name:String) + +func _ready(): + load_settings() + +func load_settings(): + if FileAccess.file_exists("user://settings.tres"): + Global.settings = load("user://settings.tres") as Settings + print("Current project dir: {0}".format([Global.settings.current_project_dir])) + print("Current map: {0}".format([Global.settings.current_map_name])) + else: + # Global data not found, writing default settings + save_settings() + + var cur_dir = Global.settings.current_project_dir + if DirAccess.dir_exists_absolute(cur_dir) and len(cur_dir)>0: + print("Project Dir exists ({0})".format([cur_dir])) + else: + print("Project Dir not found ({0})".format([cur_dir])) + choose_project_folder() + + var full_map_name = Global.settings.current_project_dir + "/" + Global.settings.current_map_name + if FileAccess.file_exists(full_map_name): + print("Loading Map: ({0})".format([full_map_name])) + else: + if DirAccess.dir_exists_absolute(cur_dir) and len(cur_dir)>0: + print("Select Map Dialog, because Dir exists: {0}".format([cur_dir])) + choose_current_map() + + +func choose_project_folder(): + print("(Choose project folder)") + %FileDialog.mode_overrides_title = false + %FileDialog.title="Projektordner festlegen" + %FileDialog.access=FileDialog.ACCESS_FILESYSTEM + + %FileDialog.file_mode = FileDialog.FILE_MODE_OPEN_DIR + %FileDialog.set_current_dir( OS.get_system_dir(OS.SYSTEM_DIR_DOCUMENTS) ) # or any other path + + %FileDialog.popup_centered() + %FileDialog.dir_selected.connect(func(dir_path): + print("Selected directory: ", dir_path) + Global.settings.current_project_dir = dir_path + save_settings() + choose_current_map() + ) + + + +func choose_current_map(): + print("(Choose current map)") + #var file_dialog1 = FileDialog.new() + %FileDialog.mode_overrides_title = false + %FileDialog.title="Karte laden" + %FileDialog.access=FileDialog.ACCESS_FILESYSTEM + %FileDialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE + print("Setting map directory to {0}".format([Global.settings.current_project_dir])) + %FileDialog.set_current_dir(Global.settings.current_project_dir) # or any other path + + %FileDialog.popup_centered() + %FileDialog.file_selected.connect(func(full_filename): + + if not full_filename.ends_with(".tres"): full_filename = full_filename + ".tres" + print("Selected file: ", full_filename) + var filename:String = full_filename.split("/")[-1] + print("Shortname: ", filename) + Global.settings.current_map_name = filename + save_settings() + + emit_signal("selected_map_for_loading", full_filename) + ) + + +func save_settings(): + ResourceSaver.save(Global.settings, "user://settings.tres") diff --git a/hexmapper/scenes/MainMap/startup.gd.uid b/hexmapper/scenes/MainMap/startup.gd.uid new file mode 100644 index 0000000..9f1b2ac --- /dev/null +++ b/hexmapper/scenes/MainMap/startup.gd.uid @@ -0,0 +1 @@ +uid://b5v0k8cmkbrsr diff --git a/project_data/westreiche/Map01.tres b/project_data/westreiche/Map01.tres new file mode 100644 index 0000000..56e5cda --- /dev/null +++ b/project_data/westreiche/Map01.tres @@ -0,0 +1,7 @@ +[gd_resource type="Resource" script_class="MapData" load_steps=2 format=3] + +[ext_resource type="Script" path="res://resources/map_data.gd" id="1_l3gjh"] + +[resource] +script = ExtResource("1_l3gjh") +cells = Array[Vector2i]([Vector2i(-2, -1), Vector2i(-1, -1), Vector2i(0, -1), Vector2i(0, 0), Vector2i(-1, 0), Vector2i(-2, 1), Vector2i(-1, 1), Vector2i(0, 1), Vector2i(-2, 0), Vector2i(-3, -1), Vector2i(-3, 0), Vector2i(-3, 1), Vector2i(-4, 0), Vector2i(-4, -1), Vector2i(4, 1), Vector2i(5, 1), Vector2i(6, 1), Vector2i(7, 1), Vector2i(7, 0), Vector2i(6, 0), Vector2i(5, 0), Vector2i(4, 0), Vector2i(7, 2), Vector2i(6, 2), Vector2i(5, 2), Vector2i(4, 2), Vector2i(2, -3), Vector2i(3, -2), Vector2i(3, -3), Vector2i(2, -2), Vector2i(1, -3), Vector2i(1, -4), Vector2i(2, -4), Vector2i(11, 3), Vector2i(11, 2), Vector2i(11, 1), Vector2i(11, 0), Vector2i(12, 0), Vector2i(11, -1), Vector2i(12, -1), Vector2i(12, -2), Vector2i(12, 1), Vector2i(12, 2), Vector2i(13, 3), Vector2i(12, 3), Vector2i(13, 4), Vector2i(12, 4), Vector2i(12, 5), Vector2i(13, 2), Vector2i(12, -10), Vector2i(12, -9), Vector2i(12, -8), Vector2i(12, -7), Vector2i(12, -6), Vector2i(12, -5), Vector2i(12, -4), Vector2i(12, -3), Vector2i(13, -10), Vector2i(13, -9), Vector2i(13, -8), Vector2i(13, -7), Vector2i(13, -6), Vector2i(13, -5), Vector2i(13, -4), Vector2i(13, -3), Vector2i(13, -2), Vector2i(14, -10), Vector2i(14, -9), Vector2i(14, -8), Vector2i(14, -7), Vector2i(14, -6), Vector2i(14, -5), Vector2i(14, -4), Vector2i(14, -3), Vector2i(14, -2), Vector2i(15, -10), Vector2i(15, -9), Vector2i(15, -8), Vector2i(15, -7), Vector2i(15, -6), Vector2i(15, -5), Vector2i(15, -4), Vector2i(15, -3), Vector2i(15, -2), Vector2i(16, -10), Vector2i(16, -9), Vector2i(16, -8), Vector2i(16, -7), Vector2i(16, -6), Vector2i(16, -5), Vector2i(16, -4), Vector2i(16, -3), Vector2i(16, -2), Vector2i(17, -10), Vector2i(17, -9), Vector2i(17, -8), Vector2i(17, -7), Vector2i(17, -6), Vector2i(17, -5), Vector2i(17, -4), Vector2i(17, -3), Vector2i(17, -2), Vector2i(18, -10), Vector2i(18, -9), Vector2i(18, -8), Vector2i(18, -7), Vector2i(18, -6), Vector2i(18, -5), Vector2i(18, -4), Vector2i(18, -3), Vector2i(18, -2), Vector2i(19, -10), Vector2i(19, -9), Vector2i(19, -8), Vector2i(19, -7), Vector2i(19, -6), Vector2i(19, -5), Vector2i(19, -4), Vector2i(19, -3), Vector2i(19, -2), Vector2i(20, -10), Vector2i(20, -9), Vector2i(20, -8), Vector2i(20, -7), Vector2i(20, -6), Vector2i(20, -5), Vector2i(20, -4), Vector2i(20, -3), Vector2i(20, -2), Vector2i(21, -10), Vector2i(21, -9), Vector2i(21, -8), Vector2i(21, -7), Vector2i(21, -6), Vector2i(21, -5), Vector2i(21, -4), Vector2i(21, -3), Vector2i(21, -2), Vector2i(5, -10), Vector2i(5, -9), Vector2i(6, -10), Vector2i(6, -9), Vector2i(7, -10), Vector2i(7, -9), Vector2i(8, -10), Vector2i(8, -9), Vector2i(9, -10), Vector2i(9, -9), Vector2i(10, -10), Vector2i(10, -9), Vector2i(11, -10), Vector2i(11, -9), Vector2i(15, -15), Vector2i(15, -14), Vector2i(15, -13), Vector2i(15, -12), Vector2i(15, -11), Vector2i(16, -15), Vector2i(16, -14), Vector2i(16, -13), Vector2i(16, -12), Vector2i(16, -11), Vector2i(17, -15), Vector2i(17, -14), Vector2i(17, -13), Vector2i(17, -12), Vector2i(17, -11), Vector2i(9, -6), Vector2i(9, -5), Vector2i(9, -4), Vector2i(10, -6), Vector2i(10, -5), Vector2i(10, -4), Vector2i(11, -6), Vector2i(11, -5), Vector2i(11, -4), Vector2i(1, 2), Vector2i(0, 2), Vector2i(-1, 2), Vector2i(-2, 2), Vector2i(-3, 2), Vector2i(-2, 3), Vector2i(-1, 3), Vector2i(0, 3), Vector2i(1, 3), Vector2i(2, 3), Vector2i(2, 2), Vector2i(1, 1), Vector2i(1, 0), Vector2i(1, -1), Vector2i(2, 0), Vector2i(2, -1), Vector2i(3, 1), Vector2i(2, 1), Vector2i(-2, -2), Vector2i(-1, -2), Vector2i(0, -2), Vector2i(0, -3), Vector2i(2, -5), Vector2i(0, -4), Vector2i(1, -2), Vector2i(3, 0), Vector2i(3, -1), Vector2i(4, -1), Vector2i(4, -2), Vector2i(5, -2), Vector2i(3, 2), Vector2i(3, 3), Vector2i(3, 4), Vector2i(2, 4), Vector2i(2, 5), Vector2i(1, 4), Vector2i(3, 5), Vector2i(4, 4), Vector2i(1, 5), Vector2i(0, 5), Vector2i(-1, 5), Vector2i(-2, 5), Vector2i(-1, 4), Vector2i(0, 4), Vector2i(-2, 4), Vector2i(8, 1), Vector2i(8, 2), Vector2i(8, 3), Vector2i(7, 3), Vector2i(7, 4), Vector2i(7, 5), Vector2i(6, 3), Vector2i(5, 3), Vector2i(5, 4), Vector2i(4, 3), Vector2i(8, 4), Vector2i(8, 0), Vector2i(9, 1), Vector2i(9, 2), Vector2i(9, 3), Vector2i(8, 5), Vector2i(8, -1), Vector2i(11, -7), Vector2i(10, -3), Vector2i(11, -2), Vector2i(13, 0), Vector2i(14, 0), Vector2i(14, -1), Vector2i(15, -1), Vector2i(19, -11), Vector2i(18, -12), Vector2i(10, -8), Vector2i(9, -8), Vector2i(10, -7), Vector2i(9, -7), Vector2i(8, -6), Vector2i(18, -11), Vector2i(11, -8), Vector2i(11, -3), Vector2i(13, -1), Vector2i(-4, 3), Vector2i(-4, 2), Vector2i(-3, 3), Vector2i(-3, 4), Vector2i(-4, 4), Vector2i(-3, 5), Vector2i(-4, 5), Vector2i(-5, 4), Vector2i(-5, 5), Vector2i(-4, 6), Vector2i(-3, 6), Vector2i(-5, 6), Vector2i(-6, 5), Vector2i(-6, 6)]) diff --git a/tools/get_hostname.py b/tools/get_hostname.py new file mode 100644 index 0000000..99024be --- /dev/null +++ b/tools/get_hostname.py @@ -0,0 +1,6 @@ +import subprocess + +result = subprocess.run(['hostname'], capture_output=True, text=True) +hostname = result.stdout.strip() +print(f"Hostname: {hostname}") + diff --git a/tools/spritesheet_creator/input/map_buildings/Church.png b/tools/spritesheet_creator/input/map_buildings/Church.png new file mode 100644 index 0000000..d74c590 Binary files /dev/null and b/tools/spritesheet_creator/input/map_buildings/Church.png differ diff --git a/tools/spritesheet_creator/input/map_buildings/Church5.png b/tools/spritesheet_creator/input/map_buildings/Church5.png new file mode 100644 index 0000000..c3aa255 Binary files /dev/null and b/tools/spritesheet_creator/input/map_buildings/Church5.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/BoulderHills1.png b/tools/spritesheet_creator/input/map_hex_terrain/BoulderHills1.png new file mode 100644 index 0000000..acdb5bc Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/BoulderHills1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Brambles1.png b/tools/spritesheet_creator/input/map_hex_terrain/Brambles1.png new file mode 100644 index 0000000..b0acde0 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Brambles1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/BrownHills1.png b/tools/spritesheet_creator/input/map_hex_terrain/BrownHills1.png new file mode 100644 index 0000000..8e2b4ea Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/BrownHills1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/BrownHills2.png b/tools/spritesheet_creator/input/map_hex_terrain/BrownHills2.png new file mode 100644 index 0000000..f43b4d2 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/BrownHills2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Brush1.png b/tools/spritesheet_creator/input/map_hex_terrain/Brush1.png new file mode 100644 index 0000000..0315fbd Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Brush1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Brush2.png b/tools/spritesheet_creator/input/map_hex_terrain/Brush2.png new file mode 100644 index 0000000..593c31c Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Brush2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Brush3.png b/tools/spritesheet_creator/input/map_hex_terrain/Brush3.png new file mode 100644 index 0000000..8d85a95 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Brush3.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Desert1.png b/tools/spritesheet_creator/input/map_hex_terrain/Desert1.png new file mode 100644 index 0000000..5f9de55 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Desert1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Desert2.png b/tools/spritesheet_creator/input/map_hex_terrain/Desert2.png new file mode 100644 index 0000000..03296b6 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Desert2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/DesertScrub1.png b/tools/spritesheet_creator/input/map_hex_terrain/DesertScrub1.png new file mode 100644 index 0000000..6a0504b Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/DesertScrub1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/DesertScrub2.png b/tools/spritesheet_creator/input/map_hex_terrain/DesertScrub2.png new file mode 100644 index 0000000..2009ce5 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/DesertScrub2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/DesertScrub4.png b/tools/spritesheet_creator/input/map_hex_terrain/DesertScrub4.png new file mode 100644 index 0000000..fb888c5 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/DesertScrub4.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Grass1.png b/tools/spritesheet_creator/input/map_hex_terrain/Grass1.png new file mode 100644 index 0000000..55d8e8c Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Grass1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Grass2.png b/tools/spritesheet_creator/input/map_hex_terrain/Grass2.png new file mode 100644 index 0000000..8730504 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Grass2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Grass3.png b/tools/spritesheet_creator/input/map_hex_terrain/Grass3.png new file mode 100644 index 0000000..589c519 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Grass3.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Hills1.png b/tools/spritesheet_creator/input/map_hex_terrain/Hills1.png new file mode 100644 index 0000000..8a53fa9 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Hills1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Hills3.png b/tools/spritesheet_creator/input/map_hex_terrain/Hills3.png new file mode 100644 index 0000000..b3f8922 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Hills3.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/HillsGreen1.png b/tools/spritesheet_creator/input/map_hex_terrain/HillsGreen1.png new file mode 100644 index 0000000..1c5980a Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/HillsGreen1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/HillsGreen2.png b/tools/spritesheet_creator/input/map_hex_terrain/HillsGreen2.png new file mode 100644 index 0000000..fa05a5a Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/HillsGreen2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/HillsGreen3.png b/tools/spritesheet_creator/input/map_hex_terrain/HillsGreen3.png new file mode 100644 index 0000000..94bb10a Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/HillsGreen3.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Lake1.png b/tools/spritesheet_creator/input/map_hex_terrain/Lake1.png new file mode 100644 index 0000000..10d1d5e Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Lake1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Lake2.png b/tools/spritesheet_creator/input/map_hex_terrain/Lake2.png new file mode 100644 index 0000000..16fcf1e Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Lake2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/LightGrass1.png b/tools/spritesheet_creator/input/map_hex_terrain/LightGrass1.png new file mode 100644 index 0000000..6cb7c53 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/LightGrass1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/LightGrass2.png b/tools/spritesheet_creator/input/map_hex_terrain/LightGrass2.png new file mode 100644 index 0000000..4706893 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/LightGrass2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/LowHills1.png b/tools/spritesheet_creator/input/map_hex_terrain/LowHills1.png new file mode 100644 index 0000000..327867f Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/LowHills1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/LowHills2.png b/tools/spritesheet_creator/input/map_hex_terrain/LowHills2.png new file mode 100644 index 0000000..d5981f6 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/LowHills2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/LowHills3.png b/tools/spritesheet_creator/input/map_hex_terrain/LowHills3.png new file mode 100644 index 0000000..855cc79 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/LowHills3.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/LowHills4.png b/tools/spritesheet_creator/input/map_hex_terrain/LowHills4.png new file mode 100644 index 0000000..e5a022b Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/LowHills4.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Mountains1.png b/tools/spritesheet_creator/input/map_hex_terrain/Mountains1.png new file mode 100644 index 0000000..a5675aa Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Mountains1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Mountains2.png b/tools/spritesheet_creator/input/map_hex_terrain/Mountains2.png new file mode 100644 index 0000000..8f6c01a Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Mountains2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Mountains5.png b/tools/spritesheet_creator/input/map_hex_terrain/Mountains5.png new file mode 100644 index 0000000..01a5859 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Mountains5.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Mud1.png b/tools/spritesheet_creator/input/map_hex_terrain/Mud1.png new file mode 100644 index 0000000..a48b89a Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Mud1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Mud2.png b/tools/spritesheet_creator/input/map_hex_terrain/Mud2.png new file mode 100644 index 0000000..ae1d940 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Mud2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Mud3.png b/tools/spritesheet_creator/input/map_hex_terrain/Mud3.png new file mode 100644 index 0000000..413b97b Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Mud3.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Ocean1.png b/tools/spritesheet_creator/input/map_hex_terrain/Ocean1.png new file mode 100644 index 0000000..fa38481 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Ocean1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Ocean2.png b/tools/spritesheet_creator/input/map_hex_terrain/Ocean2.png new file mode 100644 index 0000000..735cffa Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Ocean2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Orchards1.png b/tools/spritesheet_creator/input/map_hex_terrain/Orchards1.png new file mode 100644 index 0000000..7f2fdf9 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Orchards1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Orchards2.png b/tools/spritesheet_creator/input/map_hex_terrain/Orchards2.png new file mode 100644 index 0000000..2832cb2 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Orchards2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Rough1.png b/tools/spritesheet_creator/input/map_hex_terrain/Rough1.png new file mode 100644 index 0000000..3b496ae Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Rough1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Rough2.png b/tools/spritesheet_creator/input/map_hex_terrain/Rough2.png new file mode 100644 index 0000000..e890a92 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Rough2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/SaltBush1.png b/tools/spritesheet_creator/input/map_hex_terrain/SaltBush1.png new file mode 100644 index 0000000..0f33f72 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/SaltBush1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/SaltBush2.png b/tools/spritesheet_creator/input/map_hex_terrain/SaltBush2.png new file mode 100644 index 0000000..10fb6b7 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/SaltBush2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Snow1.png b/tools/spritesheet_creator/input/map_hex_terrain/Snow1.png new file mode 100644 index 0000000..266f6cb Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Snow1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Snow2.png b/tools/spritesheet_creator/input/map_hex_terrain/Snow2.png new file mode 100644 index 0000000..eafa449 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Snow2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Water1.png b/tools/spritesheet_creator/input/map_hex_terrain/Water1.png new file mode 100644 index 0000000..27e23df Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Water1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Water2.png b/tools/spritesheet_creator/input/map_hex_terrain/Water2.png new file mode 100644 index 0000000..b3bc837 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Water2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Woods1.png b/tools/spritesheet_creator/input/map_hex_terrain/Woods1.png new file mode 100644 index 0000000..d47cf95 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Woods1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/Woods2.png b/tools/spritesheet_creator/input/map_hex_terrain/Woods2.png new file mode 100644 index 0000000..08b73b8 Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/Woods2.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/WoodsDark1.png b/tools/spritesheet_creator/input/map_hex_terrain/WoodsDark1.png new file mode 100644 index 0000000..b59dccf Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/WoodsDark1.png differ diff --git a/tools/spritesheet_creator/input/map_hex_terrain/WoodsDark2.png b/tools/spritesheet_creator/input/map_hex_terrain/WoodsDark2.png new file mode 100644 index 0000000..37df45f Binary files /dev/null and b/tools/spritesheet_creator/input/map_hex_terrain/WoodsDark2.png differ diff --git a/tools/spritesheet_creator/input/ui/hex_cursor.png b/tools/spritesheet_creator/input/ui/hex_cursor.png new file mode 100644 index 0000000..2aa522c Binary files /dev/null and b/tools/spritesheet_creator/input/ui/hex_cursor.png differ diff --git a/tools/spritesheet_creator/mapping.txt b/tools/spritesheet_creator/mapping.txt new file mode 100644 index 0000000..f9c1aed --- /dev/null +++ b/tools/spritesheet_creator/mapping.txt @@ -0,0 +1,52 @@ +x_col,y_col,tilename +0,0,Brambles1 +0,1,Mud2 +0,2,Water2 +0,3,BrownHills2 +0,4,BoulderHills1 +0,5,LowHills2 +0,6,BrownHills1 +0,7,DesertScrub1 +1,0,Lake1 +1,1,Orchards1 +1,2,HillsGreen3 +1,3,LowHills4 +1,4,Brush2 +1,5,Grass2 +1,6,Snow2 +1,7,Water1 +2,0,Mud3 +2,1,Woods2 +2,2,Rough2 +2,3,Snow1 +2,4,Ocean1 +2,5,Desert1 +2,6,HillsGreen2 +2,7,Lake2 +3,0,WoodsDark2 +3,1,Brush1 +3,2,Desert2 +3,3,Mud1 +3,4,Rough1 +3,5,Hills1 +3,6,WoodsDark1 +3,7,LightGrass1 +4,0,Mountains2 +4,1,Mountains1 +4,2,Mountains5 +4,3,Woods1 +4,4,Hills3 +4,5,Ocean2 +4,6,Brush3 +4,7,LowHills3 +5,0,LightGrass2 +5,1,SaltBush2 +5,2,HillsGreen1 +5,3,Orchards2 +5,4,Grass3 +5,5,LowHills1 +5,6,SaltBush1 +5,7,Grass1 +6,0,Church5 +6,1,DesertScrub4 +6,2,DesertScrub2 diff --git a/tools/spritesheet_creator/mapping.txt.import b/tools/spritesheet_creator/mapping.txt.import new file mode 100644 index 0000000..a64f3e0 --- /dev/null +++ b/tools/spritesheet_creator/mapping.txt.import @@ -0,0 +1,17 @@ +[remap] + +importer="csv_translation" +type="Translation" +uid="uid://eowm7vera01u" + +[deps] + +files=["res://tools/spritesheet_creator/mapping.y.translation", "res://tools/spritesheet_creator/mapping.tilename.translation"] + +source_file="res://tools/spritesheet_creator/mapping.csv" +dest_files=["res://tools/spritesheet_creator/mapping.y.translation", "res://tools/spritesheet_creator/mapping.tilename.translation"] + +[params] + +compress=true +delimiter=0 diff --git a/tools/spritesheet_creator/output/map_buildings_72x72_mapping.txt b/tools/spritesheet_creator/output/map_buildings_72x72_mapping.txt new file mode 100644 index 0000000..3c1edf4 --- /dev/null +++ b/tools/spritesheet_creator/output/map_buildings_72x72_mapping.txt @@ -0,0 +1,3 @@ +x_col,y_col,tilename +0,0,Church5 +1,0,Church \ No newline at end of file diff --git a/tools/spritesheet_creator/output/map_buildings_72x72_spritesheet.png b/tools/spritesheet_creator/output/map_buildings_72x72_spritesheet.png new file mode 100644 index 0000000..bc9cf5c Binary files /dev/null and b/tools/spritesheet_creator/output/map_buildings_72x72_spritesheet.png differ diff --git a/tools/spritesheet_creator/output/map_hex_terrain_72x72_mapping.txt b/tools/spritesheet_creator/output/map_hex_terrain_72x72_mapping.txt new file mode 100644 index 0000000..24c4a31 --- /dev/null +++ b/tools/spritesheet_creator/output/map_hex_terrain_72x72_mapping.txt @@ -0,0 +1,51 @@ +x_col,y_col,tilename +0,0,SaltBush2 +1,0,Snow1 +2,0,Hills3 +3,0,LightGrass2 +4,0,Brush3 +5,0,Orchards2 +6,0,Brush2 +7,0,Rough2 +0,1,HillsGreen3 +1,1,Woods1 +2,1,LowHills1 +3,1,HillsGreen1 +4,1,Brush1 +5,1,LowHills3 +6,1,LowHills2 +7,1,DesertScrub4 +0,2,Mud1 +1,2,Grass1 +2,2,Orchards1 +3,2,Hills1 +4,2,Mountains2 +5,2,BrownHills1 +6,2,Water2 +7,2,Lake2 +0,3,SaltBush1 +1,3,Water1 +2,3,Lake1 +3,3,Desert2 +4,3,Mud3 +5,3,BoulderHills1 +6,3,Mountains5 +7,3,Grass3 +0,4,Grass2 +1,4,Desert1 +2,4,Mud2 +3,4,BrownHills2 +4,4,Brambles1 +5,4,HillsGreen2 +6,4,Ocean2 +7,4,WoodsDark2 +0,5,DesertScrub2 +1,5,WoodsDark1 +2,5,DesertScrub1 +3,5,Woods2 +4,5,Ocean1 +5,5,Rough1 +6,5,LightGrass1 +7,5,Mountains1 +0,6,Snow2 +1,6,LowHills4 \ No newline at end of file diff --git a/tools/spritesheet_creator/output/map_hex_terrain_72x72_spritesheet.png b/tools/spritesheet_creator/output/map_hex_terrain_72x72_spritesheet.png new file mode 100644 index 0000000..0beaf2c Binary files /dev/null and b/tools/spritesheet_creator/output/map_hex_terrain_72x72_spritesheet.png differ diff --git a/tools/spritesheet_creator/output/ui_72x72_mapping.txt b/tools/spritesheet_creator/output/ui_72x72_mapping.txt new file mode 100644 index 0000000..4d45b39 --- /dev/null +++ b/tools/spritesheet_creator/output/ui_72x72_mapping.txt @@ -0,0 +1,2 @@ +x_col,y_col,tilename +0,0,hex_cursor \ No newline at end of file diff --git a/tools/spritesheet_creator/output/ui_72x72_spritesheet.png b/tools/spritesheet_creator/output/ui_72x72_spritesheet.png new file mode 100644 index 0000000..a4f5a7f Binary files /dev/null and b/tools/spritesheet_creator/output/ui_72x72_spritesheet.png differ diff --git a/tools/spritesheet_creator/spritesheet_creator.py b/tools/spritesheet_creator/spritesheet_creator.py new file mode 100644 index 0000000..534756b --- /dev/null +++ b/tools/spritesheet_creator/spritesheet_creator.py @@ -0,0 +1,116 @@ +import pygame +import os +import shutil + +def create_spritesheet(image_paths, output_path, rows=1, padding=0): + """ + Combine multiple images into a single spritesheet. + + Args: + image_paths (list): List of paths to source images + output_path (str): Path to save the combined spritesheet + rows (int): Number of rows in the spritesheet + padding (int): Pixel padding between images + """ + if not image_paths: + raise ValueError("No images provided") + + # Load all images + images = [] + max_width = 0 + max_height = 0 + + for path in image_paths: + try: + img = pygame.image.load(path)#.convert_alpha() + images.append(img) + max_width = max(max_width, img.get_width()) + max_height = max(max_height, img.get_height()) + except pygame.error as e: + print(f"Failed to load {path}: {e}") + continue + + if not images: + raise ValueError("No valid images loaded") + + # Calculate spritesheet dimensions + cols = (len(images) + rows - 1) // rows + sheet_width = cols * (max_width + padding) - padding + sheet_height = rows * (max_height + padding) - padding + + # Create blank spritesheet surface + spritesheet = pygame.Surface((sheet_width, sheet_height), pygame.SRCALPHA) + + # Blit images onto spritesheet + for i, img in enumerate(images): + row = i // cols + col = i % cols + x = col * (max_width + padding) + y = row * (max_height + padding) + spritesheet.blit(img, (x, y)) + + # Save the spritesheet + print(f"dir: {os.getcwd()}") + pygame.image.save(spritesheet, output_path) + print(f"Spritesheet saved to {output_path}") + + return max_width, max_height + + + + +pygame.init() + +tool_root_dir = os.getcwd() + +# Because os.rmdir() only works on empty directories +if os.path.isdir(f"{tool_root_dir}/output"): shutil.rmtree(f"{tool_root_dir}/output") +os.mkdir(f"{tool_root_dir}/output") + +spritesheet_names = os.listdir(f"{tool_root_dir}/input") + +for spritesheet_name in spritesheet_names: + + source_dir=f"{tool_root_dir}/input/{spritesheet_name}" + target_dir=f"{tool_root_dir}/output/" + + filenames = os.listdir(f"{source_dir}") + + # List of image paths to combine + image_files = filenames + + cols=8 + rows=len(image_files)//cols + 1 + + print(f"Dir: {os.getcwd()}") + print(f"Target: {target_dir}") + + ## Create and save spritesheet + os.chdir(source_dir) + (tile_width, tile_height) = create_spritesheet(image_files, f"{target_dir}/{spritesheet_name}_spritesheet.png", rows, padding=1) + spritesheet_filename = f"{target_dir}/{spritesheet_name}_{tile_width}x{tile_height}_spritesheet.png" + os.rename(f"{target_dir}/{spritesheet_name}_spritesheet.png", spritesheet_filename) + + ## Create+Store metadata + mapping = ["x_col,y_col,tilename"] + + for index, filename in enumerate(image_files): + #x_col = index // cols + #y_row = index - x_col * cols + y_row = index // cols + x_col = index - y_row * cols + + print(f"[{spritesheet_name}] : {index} - [{x_col},{y_row}] -> {filename}") + tilename = filename.split(".")[0] + mapping.append( f"{x_col},{y_row},{tilename}" ) + + print(f"Wrote {spritesheet_filename}") + + + mapping_filename = f"{target_dir}/{spritesheet_name}_{tile_width}x{tile_height}_mapping.txt" + f = open(mapping_filename,"w") + f.write("\n".join(mapping)) + f.close() + print(f"Wrote {mapping_filename}") + + os.chdir(f"{tool_root_dir}") \ No newline at end of file