- assets/audio/music/zombie_industrial_loop.ogg: 57.60 s Ogg Vorbis loop generated locally with YuE2-3B on the Tesla V100 (score written for this track; vocals removed with HTDemucs). The loop is spliced at the track's structural repeat with a 0.6 s crossfade: measured seam dip <= 1.6 dB. - scripts/main.gd: "Music" AudioStreamPlayer at -11 dB, started at boot on desktop and on the start click on Web (browser autoplay policy). It forces stream.loop at runtime because the Web staging step re-imports the OGG with loop=false. - tools/test_music.gd: soundtrack test (loop, length, volume, playback, still playing after player death). - docs/MUSIC.md: source, loop construction, verification, licence. - docs/WEB-DEPLOY.md: release ab6054111f5919a8 notes. Initial commit of the project.
104 lines
2.3 KiB
GDScript
104 lines
2.3 KiB
GDScript
@tool
|
|
extends EditorImportPlugin
|
|
|
|
|
|
func _get_importer_name() -> String:
|
|
return "goldsrc.spr"
|
|
|
|
|
|
func _get_visible_name() -> String:
|
|
return "GoldSrc SPR"
|
|
|
|
|
|
func _get_recognized_extensions() -> PackedStringArray:
|
|
return PackedStringArray(["spr"])
|
|
|
|
|
|
func _get_save_extension() -> String:
|
|
return "scn"
|
|
|
|
|
|
func _get_resource_type() -> String:
|
|
return "PackedScene"
|
|
|
|
|
|
func _get_preset_count() -> int:
|
|
return 1
|
|
|
|
|
|
func _get_preset_name(preset_index: int) -> String:
|
|
return "Default"
|
|
|
|
|
|
func _get_priority() -> float:
|
|
return 1.0
|
|
|
|
|
|
func _get_import_order() -> int:
|
|
return 0
|
|
|
|
|
|
func _can_import_threaded() -> bool:
|
|
return false
|
|
|
|
|
|
func _get_import_options(_path: String, _preset_index: int) -> Array[Dictionary]:
|
|
return [
|
|
{
|
|
"name": "animation_fps",
|
|
"default_value": 10.0,
|
|
"property_hint": PROPERTY_HINT_RANGE,
|
|
"hint_string": "1.0,60.0,0.5",
|
|
},
|
|
{
|
|
"name": "loop",
|
|
"default_value": true,
|
|
},
|
|
]
|
|
|
|
|
|
func _get_option_visibility(_path: String, _option_name: StringName, _options: Dictionary) -> bool:
|
|
return true
|
|
|
|
|
|
func _import(source_file: String, save_path: String, options: Dictionary,
|
|
_platform_variants: Array[String], _gen_files: Array[String]) -> Error:
|
|
var fps: float = options.get("animation_fps", 10.0)
|
|
var loop: bool = options.get("loop", true)
|
|
|
|
var spr := GoldSrcSPR.new()
|
|
var err = spr.load_spr(source_file)
|
|
if err != OK:
|
|
push_error("SPR Importer: Failed to load '%s': %s" % [source_file, error_string(err)])
|
|
return err
|
|
|
|
var frame_count = spr.get_frame_count()
|
|
if frame_count == 0:
|
|
push_error("SPR Importer: No frames in '%s'" % source_file)
|
|
return ERR_INVALID_DATA
|
|
|
|
var sprite = spr.build_scene()
|
|
if not sprite:
|
|
push_error("SPR Importer: build_scene() failed for '%s'" % source_file)
|
|
return ERR_CANT_CREATE
|
|
|
|
var sprite_name := source_file.get_file().get_basename()
|
|
if sprite_name.is_empty():
|
|
sprite_name = "sprite_root"
|
|
sprite.name = sprite_name
|
|
|
|
# Bake import options into the SpriteAnimationPlayer child
|
|
var sap = sprite.get_node_or_null(^"SpriteAnimationPlayer")
|
|
if sap:
|
|
sap.fps = fps
|
|
sap.loop_animation = loop
|
|
|
|
var scene := PackedScene.new()
|
|
var pack_err := scene.pack(sprite)
|
|
sprite.free()
|
|
if pack_err != OK:
|
|
push_error("SPR Importer: Failed to pack scene for '%s': %s" % [source_file, error_string(pack_err)])
|
|
return pack_err
|
|
|
|
return ResourceSaver.save(scene, save_path + "." + _get_save_extension())
|