Add industrial metal soundtrack with seamless loop
- 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.
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
@tool
|
||||
extends EditorImportPlugin
|
||||
|
||||
|
||||
func _get_importer_name() -> String:
|
||||
return "goldsrc.mdl"
|
||||
|
||||
|
||||
func _get_visible_name() -> String:
|
||||
return "GoldSrc MDL"
|
||||
|
||||
|
||||
func _get_recognized_extensions() -> PackedStringArray:
|
||||
return PackedStringArray(["mdl"])
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
## What shape of scene this importer builds. 1: meshes merged into one MeshInstance3D per
|
||||
## bodypart. 2: triangle corners welded back into shared vertices.
|
||||
##
|
||||
## Godot records it in each .import file but does not act on a bump — neither --import nor an
|
||||
## editor session reimports on its own (checked on 4.7). Changing the built scene means clearing
|
||||
## .godot/imported/*.mdl-* by hand; the number is here so it is visible which build a cache came
|
||||
## from.
|
||||
func _get_format_version() -> int:
|
||||
return 2
|
||||
|
||||
|
||||
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": "scale_factor",
|
||||
"default_value": 0.025,
|
||||
"property_hint": PROPERTY_HINT_RANGE,
|
||||
"hint_string": "0.001,1.0,0.001",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
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 scale_factor: float = options.get("scale_factor", 0.025)
|
||||
|
||||
var mdl := GoldSrcMDL.new()
|
||||
mdl.set_scale_factor(scale_factor)
|
||||
|
||||
var err = mdl.load_mdl(source_file)
|
||||
if err != OK:
|
||||
push_error("MDL Importer: Failed to load '%s': %s" % [source_file, error_string(err)])
|
||||
return err
|
||||
|
||||
mdl.build_model()
|
||||
|
||||
# Reparent children to a plain Node3D so the saved scene is GDExtension-independent
|
||||
var root := Node3D.new()
|
||||
var root_name := source_file.get_file().get_basename()
|
||||
if root_name.is_empty():
|
||||
root_name = "mdl_root"
|
||||
root.name = root_name
|
||||
# GoldSrc models face -Z after axis swizzle; rotate to match GoldSrc game orientation
|
||||
root.rotation_degrees.y = 90.0
|
||||
|
||||
var children := mdl.get_children()
|
||||
for child in children:
|
||||
mdl.remove_child(child)
|
||||
root.add_child(child)
|
||||
_set_owner_recursive(root, root)
|
||||
|
||||
var scene := PackedScene.new()
|
||||
var pack_err := scene.pack(root)
|
||||
if pack_err != OK:
|
||||
push_error("MDL Importer: Failed to pack scene: %s" % error_string(pack_err))
|
||||
return pack_err
|
||||
|
||||
return ResourceSaver.save(scene, save_path + "." + _get_save_extension())
|
||||
|
||||
|
||||
func _set_owner_recursive(node: Node, owner: Node) -> void:
|
||||
for child in node.get_children():
|
||||
child.owner = owner
|
||||
_set_owner_recursive(child, owner)
|
||||
Reference in New Issue
Block a user