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:
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,22 @@
|
||||
[configuration]
|
||||
entry_symbol = "goldsrc_library_init"
|
||||
compatibility_minimum = "4.6"
|
||||
reloadable = true
|
||||
|
||||
[libraries]
|
||||
|
||||
macos.debug.arm64 = "res://addons/goldsrc/bin/libgoldsrc.macos.template_debug.arm64.dylib"
|
||||
macos.release.arm64 = "res://addons/goldsrc/bin/libgoldsrc.macos.template_release.arm64.dylib"
|
||||
macos.debug.x86_64 = "res://addons/goldsrc/bin/libgoldsrc.macos.template_debug.x86_64.dylib"
|
||||
macos.release.x86_64 = "res://addons/goldsrc/bin/libgoldsrc.macos.template_release.x86_64.dylib"
|
||||
|
||||
windows.debug.x86_64 = "res://addons/goldsrc/bin/libgoldsrc.windows.template_debug.x86_64.dll"
|
||||
windows.release.x86_64 = "res://addons/goldsrc/bin/libgoldsrc.windows.template_release.x86_64.dll"
|
||||
|
||||
linux.debug.x86_64 = "res://addons/goldsrc/bin/libgoldsrc.linux.template_debug.x86_64.so"
|
||||
linux.release.x86_64 = "res://addons/goldsrc/bin/libgoldsrc.linux.template_release.x86_64.so"
|
||||
linux.debug.arm64 = "res://addons/goldsrc/bin/libgoldsrc.linux.template_debug.arm64.so"
|
||||
linux.release.arm64 = "res://addons/goldsrc/bin/libgoldsrc.linux.template_release.arm64.so"
|
||||
|
||||
android.debug.arm64 = "res://addons/goldsrc/bin/libgoldsrc.android.template_debug.arm64.so"
|
||||
android.release.arm64 = "res://addons/goldsrc/bin/libgoldsrc.android.template_release.arm64.so"
|
||||
@@ -0,0 +1 @@
|
||||
uid://dsy8u3hdjay5p
|
||||
@@ -0,0 +1,221 @@
|
||||
@tool
|
||||
extends EditorImportPlugin
|
||||
|
||||
|
||||
func _get_importer_name() -> String:
|
||||
return "goldsrc.bsp"
|
||||
|
||||
|
||||
func _get_visible_name() -> String:
|
||||
return "GoldSrc BSP"
|
||||
|
||||
|
||||
func _get_recognized_extensions() -> PackedStringArray:
|
||||
return PackedStringArray(["bsp"])
|
||||
|
||||
|
||||
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 1 # Must run after MDL/SPR importers (order 0) so their scenes are available.
|
||||
|
||||
|
||||
# Must run on main thread — ArrayMesh/ImageTexture serialization deadlocks
|
||||
# when ResourceSaver.save() is called from import worker threads.
|
||||
func _can_import_threaded() -> bool:
|
||||
return false
|
||||
|
||||
|
||||
func _get_import_options(_path: String, _preset_index: int) -> Array[Dictionary]:
|
||||
return [
|
||||
{
|
||||
"name": "wad_directory",
|
||||
"default_value": "",
|
||||
"property_hint": PROPERTY_HINT_DIR,
|
||||
"hint_string": "",
|
||||
},
|
||||
{
|
||||
"name": "scale_factor",
|
||||
"default_value": 0.025,
|
||||
"property_hint": PROPERTY_HINT_RANGE,
|
||||
"hint_string": "0.001,1.0,0.001",
|
||||
},
|
||||
# Base res:// path for resolving entity model/sprite references.
|
||||
# Set this to the folder that mirrors your GoldSrc game root inside the
|
||||
# project (e.g. res://res), so "models/headcrab.mdl" resolves correctly.
|
||||
# Leave empty when your project root already mirrors the game root.
|
||||
{
|
||||
"name": "model_directory",
|
||||
"default_value": "",
|
||||
"property_hint": PROPERTY_HINT_DIR,
|
||||
"hint_string": "",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
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 wad_directory: String = options.get("wad_directory", "")
|
||||
var scale_factor: float = options.get("scale_factor", 0.025)
|
||||
var model_directory: String = options.get("model_directory", "")
|
||||
|
||||
var bsp := GoldSrcBSP.new()
|
||||
bsp.set_scale_factor(scale_factor)
|
||||
|
||||
bsp.load_bsp(source_file)
|
||||
|
||||
# Resolve WAD files. If an explicit directory is given, scan it; otherwise
|
||||
# read the WADs the BSP itself declares in worldspawn's "wad" key and look
|
||||
# them up next to the .bsp and at the project root — so a stock project
|
||||
# textures correctly with no per-file import config.
|
||||
if wad_directory != "":
|
||||
var dir := DirAccess.open(wad_directory)
|
||||
if dir:
|
||||
dir.list_dir_begin()
|
||||
var file_name := dir.get_next()
|
||||
while file_name != "":
|
||||
if not dir.current_is_dir() and file_name.get_extension().to_lower() == "wad":
|
||||
var wad := GoldSrcWAD.new()
|
||||
var wad_path := wad_directory.path_join(file_name)
|
||||
wad.load_wad(wad_path)
|
||||
bsp.add_wad(wad)
|
||||
file_name = dir.get_next()
|
||||
dir.list_dir_end()
|
||||
else:
|
||||
push_warning("BSP Importer: Could not open WAD directory '%s'" % wad_directory)
|
||||
else:
|
||||
_load_declared_wads(bsp, source_file)
|
||||
|
||||
bsp.build_mesh()
|
||||
|
||||
# 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 = "bsp_root"
|
||||
root.name = root_name
|
||||
|
||||
var children := bsp.get_children()
|
||||
for child in children:
|
||||
bsp.remove_child(child)
|
||||
root.add_child(child)
|
||||
|
||||
_instantiate_entity_models(root, model_directory)
|
||||
|
||||
# Bake the stripped BSP (PLANES/NODES/CLIPNODES/LEAFS/VISIBILITY/MODELS) so
|
||||
# VisibilityManager (PVS) and hull collision can both initialise from the .scn
|
||||
# without the original .bsp. Collision bodies carry only a "bsp_model" index
|
||||
# and walk up the tree to find this. build_mesh() already parked it on the BSP
|
||||
# node, so read it back rather than rebuilding the whole payload —
|
||||
# PackedByteArray is copy-on-write, so this is a refcount.
|
||||
var bsp_blob: PackedByteArray = bsp.get_meta("bsp_data", PackedByteArray())
|
||||
if not bsp_blob.is_empty():
|
||||
root.set_meta("bsp_data", bsp_blob)
|
||||
|
||||
_set_owner_recursive(root, root)
|
||||
|
||||
var scene := PackedScene.new()
|
||||
var pack_err := scene.pack(root)
|
||||
if pack_err != OK:
|
||||
push_error("BSP Importer: Failed to pack scene: %s" % error_string(pack_err))
|
||||
return pack_err
|
||||
|
||||
var save_err := ResourceSaver.save(scene, save_path + "." + _get_save_extension())
|
||||
return save_err
|
||||
|
||||
|
||||
# Load the WADs a BSP declares in worldspawn's "wad" key (a ';'-separated list
|
||||
# of GoldSrc paths). Only the basename is used; each is searched for beside the
|
||||
# .bsp first, then at the project root. This mirrors the runtime WAD lookup so
|
||||
# the editor and the game texture maps identically without any import options.
|
||||
func _load_declared_wads(bsp: GoldSrcBSP, source_file: String) -> void:
|
||||
var wad_string := ""
|
||||
for ent in bsp.get_entities():
|
||||
if ent.get("classname", "") == "worldspawn":
|
||||
wad_string = ent.get("wad", "")
|
||||
break
|
||||
|
||||
var search_dirs := [source_file.get_base_dir(), "res://"]
|
||||
var seen := {}
|
||||
for wad_path in wad_string.split(";", false):
|
||||
var wad_name := wad_path.get_file().to_lower()
|
||||
if wad_name.is_empty() or seen.has(wad_name):
|
||||
continue
|
||||
seen[wad_name] = true
|
||||
for base in search_dirs:
|
||||
var full_path: String = base.path_join(wad_name)
|
||||
if FileAccess.file_exists(full_path):
|
||||
var wad := GoldSrcWAD.new()
|
||||
if wad.load_wad(full_path) == OK:
|
||||
bsp.add_wad(wad)
|
||||
break
|
||||
|
||||
|
||||
func _set_owner_recursive(node: Node, owner: Node) -> void:
|
||||
for child in node.get_children():
|
||||
child.owner = owner
|
||||
# Don't recurse into instanced sub-scenes — their internal nodes belong
|
||||
# to that scene, not to this one. Setting owner on the root is enough.
|
||||
if child.scene_file_path == "":
|
||||
_set_owner_recursive(child, owner)
|
||||
|
||||
|
||||
# Instantiate MDL/SPR scenes for each point entity that has a "model" key.
|
||||
# Resolves entity paths relative to model_dir (if set) or res:// (if empty),
|
||||
# mirroring the GoldSrc layout at that root.
|
||||
# Falls back to a placeholder box if the asset is not found.
|
||||
func _instantiate_entity_models(root: Node3D, model_dir: String) -> void:
|
||||
var base := model_dir if model_dir != "" else "res://"
|
||||
for child in root.get_children():
|
||||
if not child.has_meta("entity"):
|
||||
continue
|
||||
var ent: Dictionary = child.get_meta("entity")
|
||||
var model_path: String = ent.get("model", "")
|
||||
|
||||
# Brush entities reference internal BSP sub-models ("*N") — skip them.
|
||||
if model_path.is_empty() or model_path.begins_with("*"):
|
||||
continue
|
||||
|
||||
var res_path := base.path_join(model_path)
|
||||
var instance: Node3D = null
|
||||
|
||||
if ResourceLoader.exists(res_path):
|
||||
var scene := load(res_path) as PackedScene
|
||||
if scene:
|
||||
instance = scene.instantiate() as Node3D
|
||||
|
||||
if instance == null:
|
||||
var mi := MeshInstance3D.new()
|
||||
var box := BoxMesh.new()
|
||||
box.size = Vector3(0.3, 0.3, 0.3)
|
||||
mi.mesh = box
|
||||
instance = mi
|
||||
push_warning("BSP Importer: model not found, using placeholder for '%s'" % res_path)
|
||||
|
||||
var node_name := model_path.get_file().get_basename()
|
||||
if node_name.is_empty():
|
||||
node_name = "unnamed_entity_model"
|
||||
instance.name = node_name
|
||||
child.add_child(instance)
|
||||
@@ -0,0 +1 @@
|
||||
uid://bkjulqpbo8sjd
|
||||
@@ -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)
|
||||
@@ -0,0 +1 @@
|
||||
uid://bp0377di4pbve
|
||||
@@ -0,0 +1,103 @@
|
||||
@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())
|
||||
@@ -0,0 +1 @@
|
||||
uid://n8cr2s2yyhqe
|
||||
@@ -0,0 +1,110 @@
|
||||
@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())
|
||||
@@ -0,0 +1 @@
|
||||
uid://dl2ri2g5ai8cf
|
||||
@@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="GoldSrc"
|
||||
description="Import GoldSrc engine assets (BSP maps, WAD textures, MDL models, SPR sprites)"
|
||||
author="goldsrc-godot"
|
||||
version="0.1.0"
|
||||
script="plugin.gd"
|
||||
@@ -0,0 +1,29 @@
|
||||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
var bsp_importer: EditorImportPlugin
|
||||
var mdl_importer: EditorImportPlugin
|
||||
var spr_importer: EditorImportPlugin
|
||||
var wad_importer: EditorImportPlugin
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
bsp_importer = preload("res://addons/goldsrc/importer/bsp_importer.gd").new()
|
||||
mdl_importer = preload("res://addons/goldsrc/importer/mdl_importer.gd").new()
|
||||
spr_importer = preload("res://addons/goldsrc/importer/spr_importer.gd").new()
|
||||
wad_importer = preload("res://addons/goldsrc/importer/wad_importer.gd").new()
|
||||
add_import_plugin(bsp_importer)
|
||||
add_import_plugin(mdl_importer)
|
||||
add_import_plugin(spr_importer)
|
||||
add_import_plugin(wad_importer)
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
remove_import_plugin(bsp_importer)
|
||||
remove_import_plugin(mdl_importer)
|
||||
remove_import_plugin(spr_importer)
|
||||
remove_import_plugin(wad_importer)
|
||||
bsp_importer = null
|
||||
mdl_importer = null
|
||||
spr_importer = null
|
||||
wad_importer = null
|
||||
@@ -0,0 +1 @@
|
||||
uid://eql0skovdole
|
||||
Reference in New Issue
Block a user