crabs-game/addons/aseprite_importer/classes/AsepriteImportData.gd

175 lines
3.0 KiB
GDScript

tool
extends Node
class_name AsepriteImportData
enum Error{
OK,
ERR_JSON_PARSE_ERROR,
ERR_INVALID_JSON_DATA,
}
const FRAME_TEMPLATE = {
frame = {
x = TYPE_INT,
y = TYPE_INT,
w = TYPE_INT,
h = TYPE_INT,
},
spriteSourceSize = {
x = TYPE_INT,
y = TYPE_INT,
w = TYPE_INT,
h = TYPE_INT,
},
sourceSize = {
w = TYPE_INT,
h = TYPE_INT,
},
duration = TYPE_INT,
}
const META_TEMPLATE = {
frameTags = [
{
name = TYPE_STRING,
from = TYPE_INT,
to = TYPE_INT,
direction = TYPE_STRING
},
],
size = {
w = TYPE_INT,
h = TYPE_INT,
},
}
var json_filepath : String
var json_data : Dictionary
func load(filepath : String) -> int:
var file := File.new()
var error := file.open(filepath, File.READ)
if error != OK:
return error
var file_text = file.get_as_text()
file.close()
var json := JSON.parse(file_text)
if json.error != OK:
return Error.ERR_JSON_PARSE_ERROR
if not _validate_json(json):
return Error.ERR_INVALID_JSON_DATA
json_filepath = filepath
json_data = json.result
return OK
func get_frame_array() -> Array:
if not json_data:
return []
var frame_data = json_data.frames
if frame_data is Dictionary:
return frame_data.values()
return frame_data
func get_image_filename() -> String:
if not (json_data and json_data.meta.has("image")):
return ""
return json_data.meta.image
func get_image_size() -> Vector2:
if not json_data:
return Vector2.ZERO
var image_size : Dictionary = json_data.meta.size
return Vector2(
image_size.w,
image_size.h
)
func get_tag(tag_idx : int) -> Dictionary:
var tags := get_tags()
if tag_idx >= 0 and tag_idx < tags.size():
return tags[tag_idx]
return {}
func get_tags() -> Array:
if not json_data:
return []
return json_data.meta.frameTags
static func _validate_json(json : JSONParseResult) -> bool:
var data : Dictionary = json.result
if not (data is Dictionary and data.has_all(["frames", "meta"])):
return false
# "frames" validation
var frames = data.frames
var is_hash := frames is Dictionary
for frame in frames:
if is_hash:
frame = frames[frame]
if not _match_template(frame, FRAME_TEMPLATE):
return false
# "meta" validation
return _match_template(data.meta, META_TEMPLATE)
"""
This helper function recursively walks an Array or a Dictionary checking if each
children's type matches the template
"""
static func _match_template(data, template) -> bool:
match typeof(template):
TYPE_INT:
# When parsed, the JSON interprets integer values as floats
if template == TYPE_INT and typeof(data) == TYPE_REAL:
return true
return typeof(data) == template
TYPE_DICTIONARY:
if typeof(data) != TYPE_DICTIONARY:
return false
if not data.has_all(template.keys()):
return false
for key in template:
if not _match_template(data[key], template[key]):
return false
TYPE_ARRAY:
if typeof(data) != TYPE_ARRAY:
return false
if data.empty():
return false
for element in data:
if not _match_template(element, template[0]):
return false
return true