Add addons

This commit is contained in:
Joey Yakimowich-Payne 2023-01-03 16:53:53 -07:00
commit 3367bad24f
No known key found for this signature in database
GPG key ID: 6BFE655FA5ABD1E1
527 changed files with 36197 additions and 0 deletions

View file

@ -0,0 +1,352 @@
@tool
extends RefCounted
var result_code = preload("../config/result_codes.gd")
var _aseprite = preload("../aseprite/aseprite.gd").new()
enum {
FILE_EXPORT_MODE,
LAYERS_EXPORT_MODE
}
var _config
var _file_system: EditorFileSystem
var _should_check_file_system := false
func init(config, editor_file_system: EditorFileSystem = null):
_config = config
_file_system = editor_file_system
_should_check_file_system = _file_system != null
_aseprite.init(config)
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
func create_animations(sprite: Node, options: Dictionary) -> void:
var input_check = _initial_checks(options.source, options)
if input_check != result_code.SUCCESS:
printerr(result_code.get_error_message(input_check))
return
var result = await _create_animations_from_file(sprite, options)
if result != result_code.SUCCESS:
printerr(result_code.get_error_message(result))
func _create_animations_from_file(animated_sprite: Node, options: Dictionary) -> int:
var output = _export_aseprite_file(options)
if not output.is_ok:
return output.code
if _config.is_import_preset_enabled():
_config.create_import_file(output.content)
await _scan_filesystem()
var sprite_frames_result = _create_sprite_frames(output.content)
if not sprite_frames_result.is_ok:
return sprite_frames_result.code
animated_sprite.frames = sprite_frames_result.content
animated_sprite.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
if _config.should_remove_source_files():
DirAccess.remove_absolute(output.content.data_file)
return result_code.SUCCESS
func _export_aseprite_file(options: Dictionary) -> Dictionary:
var output
if options.get("layer", "") == "":
output = _aseprite.export_file(options.source, options.output_folder, options)
else:
output = _aseprite.export_layer(options.source, options.layer, options.output_folder, options)
if output.is_empty():
return result_code.error(result_code.ERR_ASEPRITE_EXPORT_FAILED)
return result_code.result(output)
func create_and_save_resources(source_file: String, options: Dictionary) -> int:
var resources = await create_resources(source_file, options)
if resources.is_ok:
return _save_resources(resources.content)
return resources.code
func create_resources(source_file: String, options = {}) -> Dictionary:
var input_check = _initial_checks(source_file, options)
if input_check != result_code.SUCCESS:
return result_code.error(input_check)
var output = _create_aseprite_output_files(source_file, options)
if not output.is_ok:
return output
await _scan_filesystem()
var result = await _create_sprite_frames_from_source(output.content, options)
if not result.is_ok:
return result
var should_remove_source = options.get("remove_source_files_allowed", false) and _config.should_remove_source_files()
if should_remove_source:
_remove_source_files(result.content)
return result
func _remove_source_files(source_files: Array):
for s in source_files:
DirAccess.remove_absolute(s.data_file)
await _scan_filesystem()
func _create_aseprite_output_files(source_file: String, options: Dictionary):
match options.get('export_mode', FILE_EXPORT_MODE):
FILE_EXPORT_MODE:
return result_code.result(
[_aseprite.export_file(source_file, options.output_folder, options)]
)
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)
func _create_sprite_frames_from_source(source_files: Array, options: Dictionary) -> Dictionary:
var should_remove_source = options.get("remove_source_files_allowed", false) and _config.should_remove_source_files()
var resources = []
for o in source_files:
if o.is_empty():
return result_code.error(result_code.ERR_ASEPRITE_EXPORT_FAILED)
var resource = _create_sprite_frames(o)
if not resource.is_ok:
return resource
resources.push_back({
"data_file": o.data_file,
"resource": resource.content,
})
return result_code.result(resources)
func _create_sprite_frames(data) -> Dictionary:
var aseprite_resources = _load_aseprite_resources(data)
if not aseprite_resources.is_ok:
return aseprite_resources
return result_code.result(
_create_sprite_frames_with_animations(
aseprite_resources.content.metadata,
aseprite_resources.content.texture
)
)
func _load_aseprite_resources(aseprite_data: Dictionary):
var content_result = _load_json_content(aseprite_data.data_file)
if not content_result.is_ok:
return content_result
var texture = _parse_texture_path(aseprite_data.sprite_sheet)
return result_code.result({
"metadata": content_result.content,
"texture": texture
})
func _load_json_content(source_file: String) -> Dictionary:
var file = FileAccess.open(source_file, FileAccess.READ)
if file == null:
return result_code.error(file.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)
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, texture) -> SpriteFrames:
var frame_cache = {}
var frames = _aseprite.get_content_frames(content)
var sprite_frames := SpriteFrames.new()
sprite_frames.remove_animation("default")
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, tag.direction, frame_cache)
else:
_add_animation_frames(sprite_frames, "default", frames, texture)
return sprite_frames
func _add_animation_frames(
sprite_frames: SpriteFrames,
anim_name: String,
frames : Array,
texture,
direction = 'forward',
frame_cache = {}
):
var animation_name := anim_name
var is_loopable = _is_loop_config_enabled()
var loop_prefix := _loop_config_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)
if direction == 'reverse':
frames.reverse()
for frame in frames:
_add_to_sprite_frames(sprite_frames, animation_name, texture, frame, min_duration, frame_cache)
if direction == 'pingpong':
frames.remove_at(frames.size() - 1)
if is_loopable:
frames.remove_at(0)
frames.reverse()
for frame in frames:
_add_to_sprite_frames(sprite_frames, animation_name, texture, frame, min_duration, frame_cache)
sprite_frames.set_animation_loop(animation_name, is_loopable)
sprite_frames.set_animation_speed(animation_name, fps)
func _calculate_fps(min_duration: int) -> float:
return ceil(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 _parse_texture_path(path):
return ResourceLoader.load(path, 'Image', ResourceLoader.CACHE_MODE_REPLACE)
func _add_to_sprite_frames(
sprite_frames,
animation_name: String,
texture,
frame: Dictionary,
min_duration: int,
frame_cache: Dictionary
):
var atlas : AtlasTexture = _create_atlastexture_from_frame(texture, frame, sprite_frames, frame_cache)
var number_of_sprites = ceil(frame.duration / min_duration)
for _i in range(number_of_sprites):
sprite_frames.add_frame(animation_name, atlas)
func _create_atlastexture_from_frame(
image,
frame_data,
sprite_frames: SpriteFrames,
frame_cache: Dictionary
) -> AtlasTexture:
var frame = frame_data.frame
var region := Rect2(frame.x, frame.y, frame.w, frame.h)
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 _scan_filesystem():
_file_system.scan()
await _file_system.filesystem_changed
func list_layers(file: String, only_visibles = false) -> Array:
return _aseprite.list_layers(file, only_visibles)
func _get_file_basename(file_path: String) -> String:
return file_path.get_file().trim_suffix('.%s' % file_path.get_extension())
func _loop_config_prefix() -> String:
return _config.get_animation_loop_exception_prefix()
func _is_loop_config_enabled() -> bool:
return _config.is_default_animation_loop_enabled()