- 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.
111 lines
2.7 KiB
GDScript
111 lines
2.7 KiB
GDScript
@tool
|
|
extends EditorImportPlugin
|
|
## Imports a GoldSrc WAD file.
|
|
##
|
|
## The WAD is saved as a minimal .tres marker so Godot tracks it as a known
|
|
## asset. The BSP importer loads WAD files directly via the C++ GoldSrcWAD
|
|
## class — it does not use extracted PNGs.
|
|
##
|
|
## PNG extraction is opt-in (extract_textures = false by default) for cases
|
|
## where individual textures are needed outside of BSP rendering.
|
|
|
|
|
|
func _get_importer_name() -> String:
|
|
return "goldsrc.wad"
|
|
|
|
|
|
func _get_visible_name() -> String:
|
|
return "GoldSrc WAD"
|
|
|
|
|
|
func _get_recognized_extensions() -> PackedStringArray:
|
|
return PackedStringArray(["wad"])
|
|
|
|
|
|
func _get_save_extension() -> String:
|
|
return "tres"
|
|
|
|
|
|
func _get_resource_type() -> String:
|
|
return "Resource"
|
|
|
|
|
|
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": "extract_textures",
|
|
"default_value": false,
|
|
},
|
|
{
|
|
"name": "output_directory",
|
|
"default_value": "",
|
|
"property_hint": PROPERTY_HINT_DIR,
|
|
"hint_string": "Leave empty to extract next to the WAD file",
|
|
},
|
|
]
|
|
|
|
|
|
func _get_option_visibility(_path: String, _option_name: StringName, _options: Dictionary) -> bool:
|
|
if _option_name == "output_directory":
|
|
return _options.get("extract_textures", true)
|
|
return true
|
|
|
|
|
|
func _import(source_file: String, save_path: String, options: Dictionary,
|
|
_platform_variants: Array[String], _gen_files: Array[String]) -> Error:
|
|
var extract: bool = options.get("extract_textures", true)
|
|
|
|
var wad := GoldSrcWAD.new()
|
|
var err = wad.load_wad(source_file)
|
|
if err != OK:
|
|
push_error("WAD Importer: Failed to load '%s': %s" % [source_file, error_string(err)])
|
|
return err
|
|
|
|
if extract:
|
|
var output_dir: String = options.get("output_directory", "")
|
|
if output_dir.is_empty():
|
|
# Default: create a folder named after the WAD next to it
|
|
output_dir = source_file.get_base_dir().path_join(
|
|
source_file.get_file().get_basename())
|
|
|
|
DirAccess.make_dir_recursive_absolute(output_dir)
|
|
|
|
var names = wad.get_texture_names()
|
|
var count := 0
|
|
for tex_name in names:
|
|
var tex = wad.get_texture(tex_name)
|
|
if tex == null:
|
|
continue
|
|
var img = tex.get_image()
|
|
if img == null:
|
|
continue
|
|
var png_path := output_dir.path_join(tex_name.to_lower() + ".png")
|
|
img.save_png(png_path)
|
|
count += 1
|
|
|
|
print("WAD Importer: Extracted %d textures to %s" % [count, output_dir])
|
|
|
|
# Save a minimal marker resource so Godot considers the import complete
|
|
var res := Resource.new()
|
|
return ResourceSaver.save(res, save_path + "." + _get_save_extension())
|