summaryrefslogtreecommitdiff
path: root/extractor/grf.gd
diff options
context:
space:
mode:
authorDaniel Weipert <git@mail.dweipert.de>2024-12-12 02:12:52 +0100
committerDaniel Weipert <git@mail.dweipert.de>2024-12-12 02:12:52 +0100
commita22381eff3bf2286ee27f4d15ddf4c431ea063be (patch)
tree965bdcf12e5e0cf63c88cbba1bd5a52ba474f81f /extractor/grf.gd
parente3c185e05823e30eccd7728ceda2ee57cc66fd4d (diff)
next commit
Diffstat (limited to 'extractor/grf.gd')
-rw-r--r--extractor/grf.gd208
1 files changed, 204 insertions, 4 deletions
diff --git a/extractor/grf.gd b/extractor/grf.gd
index 7e7e93c..fa7021a 100644
--- a/extractor/grf.gd
+++ b/extractor/grf.gd
@@ -140,7 +140,7 @@ class FileEntry:
@warning_ignore("shadowed_variable")
static func from_bytes_with_filename(bytes: PackedByteArray, file_name: String):
- print(file_name)
+ #print(file_name)
var file_entry = FileEntry.new()
file_entry.file_name = file_name
@@ -199,14 +199,214 @@ func extract(destination: String = "res://data"):
var file = FileAccess.open("%s/extracted/%s" % [destination, file_path], FileAccess.WRITE_READ)
file.store_buffer(file_entry.get_contents(file_access))
-
- # TODO: write pngs for sprites (and .tres files maybe if necessary)
- # TODO: (also maybe write .tres files for action data files(whatever they are))
+func convert(destination: String = "res://data"):
+ for file_entry in file_entries:
+ var file_path: String = file_entry.get_file_path()
+
+ var base_directory = DirAccess.open(destination)
+ var base_directory_path = "extracted/%s" % file_path.get_base_dir()
+ base_directory.make_dir_recursive(base_directory_path)
+ base_directory.change_dir(base_directory_path)
+
+ var file_name = file_path.get_file().substr(0,
+ file_path.get_file().length() - (file_path.get_extension().length() + 1)
+ )
+ var base_file_directory_path := "%s/%s" % [base_directory.get_current_dir(), file_name]
+
+ #DirAccess.make_dir_recursive_absolute(base_file_directory_path)
+
+ if file_path.ends_with(".spr") and file_path.contains("cursors"):
+ var sprite = SpriteFormat.from_bytes(file_entry.get_contents(file_access))
+ sprite.save_to_file(base_file_directory_path)
+
+ elif file_path.ends_with(".act") and file_path.contains("cursors"):
+ if not FileAccess.file_exists("%s/000.png.import" % base_file_directory_path):
+ continue
+
+ var scene := PackedScene.new()
+ var scene_root := Node2D.new()
+ scene_root.name = "Actions"
+ scene_root.set_script(load("res://extractor/actions.gd"))
+
+ var animation_player := AnimationPlayer.new()
+ animation_player.name = "AnimationPlayer"
+ animation_player.unique_name_in_owner = true
+ scene_root.add_child(animation_player)
+ animation_player.owner = scene_root
+
+ var sprite_layers := CanvasGroup.new()
+ sprite_layers.name = "SpriteLayers"
+ sprite_layers.unique_name_in_owner = true
+
+ scene_root.add_child(sprite_layers)
+ sprite_layers.owner = scene_root
+
+ var track_properties = [
+ "animation",
+ "frame",
+ "speed_scale",
+ "position",
+ "self_modulate",
+ "scale",
+ "rotation_degrees",
+ "flip_h",
+ "visible",
+ ]
+
+ var sprite_frames := SpriteFrames.new()
+ #sprite_frames.add_animation("default")
+ for img_file_path in DirAccess.get_files_at(base_file_directory_path):
+ if img_file_path.ends_with(".png"):
+ sprite_frames.add_frame("default", load("%s/%s" % [base_file_directory_path, img_file_path]))
+
+ var animation_library := AnimationLibrary.new()
+ var action_data := ActionFormat.from_bytes(ByteStream.from_bytes(file_entry.get_contents(file_access)))
+
+ # get max number of sprite layers for all actions
+ var action_sprite_layers_max_count = action_data.actions.reduce(func(accum, action: ActionFormat.ActionData):
+ return max(accum, action.motions.reduce(func(accum2, motion: ActionFormat.Motion):
+ return max(accum2, motion.sprite_layer_count)
+ , 0))
+ , 0)
+
+ # add Nodes for each sprite layer
+ for sprite_layer_idx in action_sprite_layers_max_count:
+ var sprite = AnimatedSprite2D.new()
+ sprite.centered = false # 必要!!
+ sprite.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
+ sprite.sprite_frames = sprite_frames
+ sprite.name = str(sprite_layer_idx).pad_zeros(3)
+ sprite_layers.add_child(sprite)
+ sprite.owner = scene_root
+
+ for action_idx in action_data.actions.size():
+ var action: ActionFormat.ActionData = action_data.actions[action_idx]
+ var frame_timing_base := ((action_data.frame_times[action_idx] * 24) / 1000)
+
+ if file_path.contains("cursors") and action_idx == 0:
+ frame_timing_base = ((action_data.frame_times[action_idx] * 24 * 2) / 1000)
+
+ # add animation for each action
+ var animation := Animation.new()
+ animation.loop_mode = Animation.LOOP_LINEAR
+ animation.length = frame_timing_base * action.motion_count
+ animation_library.add_animation(str(action_idx).pad_zeros(3), animation)
+
+ # TODO: set animation max length
+
+ # get max number of sprite layers for current action motions
+ var motion_sprite_layers_max_count = action.motions.reduce(func(accum, motion: ActionFormat.Motion):
+ return max(accum, motion.sprite_layer_count)
+ , 0)
+
+ # add animation tracks for each sprite layer
+ for sprite_layer_idx in motion_sprite_layers_max_count:
+ var sprite := sprite_layers.get_child(sprite_layer_idx)
+ for property_idx in track_properties.size():
+ var track_idx = (sprite_layer_idx * track_properties.size()) + property_idx
+ animation.add_track(Animation.TYPE_VALUE, track_idx)
+ animation.value_track_set_update_mode(track_idx, Animation.UPDATE_DISCRETE)
+ animation.track_set_path(
+ track_idx,
+ "%s:%s" % ["SpriteLayers/" + sprite.name, track_properties[property_idx]]
+ )
+
+ for i in range(motion_sprite_layers_max_count, action_sprite_layers_max_count):
+ var sprite := sprite_layers.get_child(i)
+ var track_idx = animation.add_track(Animation.TYPE_VALUE)
+ animation.track_set_path(
+ track_idx,
+ "%s:visible" % ["SpriteLayers/" + sprite.name]
+ )
+ animation.track_insert_key(track_idx, 0.0, false)
+
+ # add animation tracks
+ for motion_idx in action.motions.size():
+ var motion: ActionFormat.Motion = action.motions[motion_idx]
+
+ var timing = motion_idx * frame_timing_base
+ var visible_key = 0
+
+ # add visible = false animation tracks to other sprite_layers
+ for i in motion_sprite_layers_max_count:
+ var track_idx = i * track_properties.size() + track_properties.find("visible")
+ visible_key = animation.track_insert_key(track_idx, timing, false)
+
+ for sprite_layer_idx in motion.sprite_layers.size():
+ var layer: ActionFormat.SpriteLayer = motion.sprite_layers[sprite_layer_idx]
+
+ var track_base_idx = sprite_layer_idx * track_properties.size()
+
+ animation.track_insert_key(
+ track_base_idx + track_properties.find("animation"),
+ timing,
+ "default"
+ )
+
+ animation.track_insert_key(
+ track_base_idx + track_properties.find("frame"),
+ timing,
+ layer.sprite_index
+ )
+
+ animation.track_insert_key(
+ track_base_idx + track_properties.find("speed_scale"),
+ timing,
+ 1.0
+ )
+
+ var layer_image := sprite_frames.get_frame_texture("default", layer.sprite_index)
+ var position: Vector2 = layer.get_position() - ceil(layer_image.get_size() / 2) # for fixing half pixel drawing
+ var rotated = layer_image.get_size().rotated(deg_to_rad(layer.rotation_degrees))
+ var distance = layer_image.get_size() - rotated
+ animation.track_insert_key(
+ track_base_idx + track_properties.find("position"),
+ timing,
+ position + (distance / 2)
+ )
+
+ animation.track_insert_key(
+ track_base_idx + track_properties.find("self_modulate"),
+ timing,
+ layer.get_color()
+ )
+
+ animation.track_insert_key(
+ track_base_idx + track_properties.find("scale"),
+ timing,
+ layer.get_scale()
+ )
+
+ animation.track_insert_key(
+ track_base_idx + track_properties.find("rotation_degrees"),
+ timing,
+ layer.rotation_degrees
+ )
+
+ animation.track_insert_key(
+ track_base_idx + track_properties.find("flip_h"),
+ timing,
+ layer.flip_h
+ )
+
+ animation.track_set_key_value(
+ track_base_idx + track_properties.find("visible"),
+ visible_key,
+ true
+ )
+
+ animation_player.add_animation_library("", animation_library)
+ scene.pack(scene_root)
+
+ # TODO: doesn't work if png is not imported via editor focus => run game twice
+ ResourceSaver.save(scene, "%s/actions.tscn" % base_file_directory_path)
+
static func decode_string(bytes: PackedByteArray):
return bytes.get_string_from_ascii()
+ @warning_ignore("unreachable_code")
# TODO: check unicode codepoints and parse accordingly
var string = bytes.get_string_from_utf32()
if string == "":