257 lines
8.6 KiB
GDScript3
257 lines
8.6 KiB
GDScript3
|
@tool class_name FmodBankExplorer extends Window
|
||
|
|
||
|
enum ToDisplayFlags {
|
||
|
BANKS = 1,
|
||
|
BUSES = 2,
|
||
|
VCA = 4,
|
||
|
EVENTS = 8
|
||
|
}
|
||
|
|
||
|
static var _fmod_icon = load("res://addons/fmod/icons/fmod_icon.svg")
|
||
|
static var _vca_icon = load("res://addons/fmod/icons/vca_icon.svg")
|
||
|
static var _bank_icon = load("res://addons/fmod/icons/bank_icon.svg")
|
||
|
static var _event_icon = load("res://addons/fmod/icons/event_icon.svg")
|
||
|
static var _bus_icon = load("res://addons/fmod/icons/bus_icon.svg")
|
||
|
static var _snapshot_icon = load("res://addons/fmod/icons/snapshot_icon.svg")
|
||
|
|
||
|
signal emit_path_and_guid(path: String, guid: String)
|
||
|
|
||
|
var tree: Tree
|
||
|
@onready var copy_path_button := %PathLabel.get_child(0)
|
||
|
@onready var copy_guid_button := %GuidLabel.get_child(0)
|
||
|
|
||
|
var should_display_copy_buttons = true
|
||
|
var should_display_select_button = false
|
||
|
|
||
|
var _current_select_callable: Callable
|
||
|
|
||
|
var base_color: Color
|
||
|
var contrast: float
|
||
|
var background_color: Color
|
||
|
|
||
|
func _ready():
|
||
|
var main_window_size = get_parent().get_window().size
|
||
|
size = main_window_size * 0.5
|
||
|
|
||
|
var copy_texture : Texture = EditorInterface.get_editor_theme().get_icon("ActionCopy", "EditorIcons")
|
||
|
copy_guid_button.icon = copy_texture
|
||
|
copy_path_button.icon = copy_texture
|
||
|
copy_guid_button.visible = false
|
||
|
copy_path_button.visible = false
|
||
|
copy_path_button.pressed.connect(_on_copy_path_button)
|
||
|
copy_guid_button.pressed.connect(_on_copy_guid_button)
|
||
|
|
||
|
var emit_path_and_guid_callable = func emit_path_and_guid_callable():
|
||
|
var selected_item = tree.get_selected()
|
||
|
if selected_item == null:
|
||
|
return
|
||
|
var selected_fmod_element = selected_item.get_metadata(0)
|
||
|
if selected_fmod_element == null:
|
||
|
return
|
||
|
|
||
|
var path = selected_fmod_element.get_godot_res_path() if selected_fmod_element is FmodBank else selected_fmod_element.get_path()
|
||
|
emit_path_and_guid.emit(path, selected_fmod_element.get_guid())
|
||
|
%SelectButton.pressed.connect(emit_path_and_guid_callable)
|
||
|
%SelectButton.pressed.connect(close_window)
|
||
|
%CloseButton.pressed.connect(close_window)
|
||
|
close_requested.connect(close_window)
|
||
|
|
||
|
tree = %Tree
|
||
|
tree.item_selected.connect(_on_item_selected)
|
||
|
|
||
|
tree.columns = 1
|
||
|
regenerate_tree(ToDisplayFlags.BANKS | ToDisplayFlags.BUSES | ToDisplayFlags.VCA | ToDisplayFlags.EVENTS)
|
||
|
|
||
|
%RefreshBanksButton.pressed.connect(on_refresh_banks_button_pressed)
|
||
|
|
||
|
|
||
|
func regenerate_tree(to_display: int, callable: Callable = Callable()):
|
||
|
%SelectButton.visible = should_display_select_button
|
||
|
if _current_select_callable != Callable() && _current_select_callable.get_object() != null:
|
||
|
emit_path_and_guid.disconnect(_current_select_callable)
|
||
|
_current_select_callable = callable
|
||
|
|
||
|
tree.clear()
|
||
|
var root_item := tree.create_item()
|
||
|
root_item.set_text(0, "Fmod objects")
|
||
|
root_item.set_icon(0, _fmod_icon)
|
||
|
|
||
|
for bank in FmodServer.get_all_banks():
|
||
|
var fmod_bank := bank as FmodBank
|
||
|
|
||
|
var bank_item := tree.create_item(root_item)
|
||
|
bank_item.set_text(0, fmod_bank.get_godot_res_path())
|
||
|
bank_item.set_icon(0, _bank_icon)
|
||
|
bank_item.set_metadata(0, bank)
|
||
|
|
||
|
if to_display & ToDisplayFlags.BUSES:
|
||
|
var buses_item := tree.create_item(bank_item)
|
||
|
buses_item.set_text(0, "Buses")
|
||
|
buses_item.set_icon(0, _bus_icon)
|
||
|
|
||
|
var buses := fmod_bank.get_bus_list()
|
||
|
buses.sort_custom(sort_by_path)
|
||
|
_add_elements_as_tree(buses, buses_item)
|
||
|
|
||
|
if to_display & ToDisplayFlags.VCA:
|
||
|
var vca_item := tree.create_item(bank_item)
|
||
|
vca_item.set_text(0, "VCAs")
|
||
|
vca_item.set_icon(0, _vca_icon)
|
||
|
|
||
|
var vcas := fmod_bank.get_vca_list()
|
||
|
vcas.sort_custom(sort_by_path)
|
||
|
_add_elements_as_tree(vcas, vca_item)
|
||
|
|
||
|
if to_display & ToDisplayFlags.EVENTS:
|
||
|
var events_item := tree.create_item(bank_item)
|
||
|
events_item.set_text(0, "Events")
|
||
|
events_item.set_icon(0, _event_icon)
|
||
|
|
||
|
var events := fmod_bank.get_description_list()
|
||
|
events.sort_custom(sort_by_path)
|
||
|
_add_elements_as_tree(events, events_item)
|
||
|
|
||
|
if copy_path_button.visible:
|
||
|
copy_path_button.visible = should_display_copy_buttons
|
||
|
|
||
|
if copy_guid_button.visible:
|
||
|
copy_guid_button.visible = should_display_copy_buttons
|
||
|
|
||
|
if _current_select_callable != Callable():
|
||
|
print(_current_select_callable)
|
||
|
emit_path_and_guid.connect(_current_select_callable)
|
||
|
|
||
|
%SelectButton.visible = should_display_select_button and %GuidLabel.text != ""
|
||
|
|
||
|
|
||
|
func _add_elements_as_tree(elements: Array, parent: TreeItem):
|
||
|
var stack = Array()
|
||
|
for element in elements:
|
||
|
_add_element_to_stack(stack, parent, element)
|
||
|
|
||
|
|
||
|
func _add_element_to_stack(stack: Array, parent_root: TreeItem, path_element):
|
||
|
var fmod_path: String = path_element.get_path()
|
||
|
var path_parts := fmod_path.split("/")
|
||
|
if path_parts[path_parts.size() - 1] == "":
|
||
|
path_parts.remove_at(path_parts.size() - 1)
|
||
|
|
||
|
for i in range(0, path_parts.size()):
|
||
|
var path_part = path_parts[i]
|
||
|
path_part = path_part if path_part != "bus:" else "Master"
|
||
|
|
||
|
if i >= stack.size():
|
||
|
var parent_item = parent_root if stack.is_empty() else stack[stack.size() - 1]
|
||
|
var tree_item = tree.create_item(parent_item)
|
||
|
tree_item.set_text(0, path_part)
|
||
|
if i == path_parts.size() - 1:
|
||
|
tree_item.set_metadata(0, path_element)
|
||
|
tree_item.set_icon(0, _get_icon_for_fmod_path(fmod_path))
|
||
|
stack.append(tree_item)
|
||
|
continue
|
||
|
|
||
|
if stack[i].get_text(0) != path_part:
|
||
|
for j in range(stack.size() - 1, i - 1, -1):
|
||
|
stack.remove_at(j)
|
||
|
|
||
|
var parent_item = parent_root if stack.is_empty() else stack[stack.size() - 1]
|
||
|
var tree_item = tree.create_item(parent_item)
|
||
|
tree_item.set_text(0, path_part)
|
||
|
if i == path_parts.size() - 1:
|
||
|
tree_item.set_metadata(0, path_element)
|
||
|
tree_item.set_icon(0, _get_icon_for_fmod_path(fmod_path))
|
||
|
stack.append(tree_item)
|
||
|
|
||
|
|
||
|
func _on_item_selected():
|
||
|
var metadata = tree.get_selected().get_metadata(0)
|
||
|
if metadata == null or !metadata.get_guid():
|
||
|
%PathsBG.hide()
|
||
|
%EventPlayControls.hide()
|
||
|
copy_path_button.visible = false
|
||
|
copy_guid_button.visible = false
|
||
|
%SelectButton.visible = false
|
||
|
%ParametersLabel.visible = false
|
||
|
%ParametersContainer.visible = false
|
||
|
return
|
||
|
%GuidLabel.set_text(metadata.get_guid())
|
||
|
%PathLabel.set_text(metadata.get_path())
|
||
|
%PathsBG.show()
|
||
|
if should_display_copy_buttons:
|
||
|
copy_path_button.visible = true
|
||
|
copy_guid_button.visible = true
|
||
|
if should_display_select_button:
|
||
|
%SelectButton.visible = true
|
||
|
|
||
|
if metadata is FmodEventDescription:
|
||
|
%EventPlayControls.set_fmod_event(metadata)
|
||
|
var _show_parameter_controls : bool = %EventParametersDisplay.set_fmod_event(metadata)
|
||
|
%ParametersLabel.visible = _show_parameter_controls
|
||
|
%ParametersContainer.visible = _show_parameter_controls
|
||
|
return
|
||
|
%EventPlayControls.hide()
|
||
|
%EventParametersDisplay.hide()
|
||
|
%ParametersLabel.visible = false
|
||
|
%ParametersContainer.visible = false
|
||
|
|
||
|
func _on_copy_path_button():
|
||
|
DisplayServer.clipboard_set(%PathLabel.text)
|
||
|
|
||
|
func _on_copy_guid_button():
|
||
|
DisplayServer.clipboard_set(%GuidLabel.text)
|
||
|
|
||
|
|
||
|
func on_refresh_banks_button_pressed() -> void:
|
||
|
# unload banks
|
||
|
var current_banks : Array = FmodServer.get_all_banks()
|
||
|
for i : FmodBank in current_banks:
|
||
|
FmodServer.unload_bank(i.get_godot_res_path())
|
||
|
# get the banks to load
|
||
|
var path : String = ProjectSettings.get_setting("Fmod/General/banks_path", "")
|
||
|
if !path:
|
||
|
printerr("No banks path set in the project settings (Fmod/General/banks_path)")
|
||
|
return # no path set in the project settings
|
||
|
var bank_paths_to_load : Array[String]
|
||
|
var dir : DirAccess = DirAccess.open(path)
|
||
|
if dir:
|
||
|
dir.list_dir_begin()
|
||
|
var file_name : String = dir.get_next()
|
||
|
while file_name != "":
|
||
|
if dir.current_is_dir():
|
||
|
pass # the found item is a directory
|
||
|
else:
|
||
|
if file_name.ends_with(".bank"):
|
||
|
bank_paths_to_load.append(path + "/" + file_name)
|
||
|
file_name = dir.get_next()
|
||
|
if bank_paths_to_load:
|
||
|
# sort to first load the master bank and its strings
|
||
|
bank_paths_to_load.sort_custom(func(path1 : String, path2 : String) -> bool: return path1.contains("Master"))
|
||
|
else:
|
||
|
printerr("Could not find any banks in the specified directory")
|
||
|
for bank_path : String in bank_paths_to_load:
|
||
|
FmodServer.load_bank(bank_path, FmodServer.FMOD_STUDIO_LOAD_BANK_NORMAL)
|
||
|
else:
|
||
|
printerr("Couldn't access bank path, please make sure you specified a folder with the banks as direct children")
|
||
|
|
||
|
regenerate_tree(ToDisplayFlags.BANKS | ToDisplayFlags.BUSES | ToDisplayFlags.VCA | ToDisplayFlags.EVENTS)
|
||
|
|
||
|
|
||
|
func close_window():
|
||
|
%EventPlayControls.stop_event()
|
||
|
visible = false
|
||
|
|
||
|
static func _get_icon_for_fmod_path(fmod_path: String) -> Texture2D:
|
||
|
var icon: Texture2D = null
|
||
|
if fmod_path.begins_with("bus:/"):
|
||
|
icon = _bus_icon
|
||
|
elif fmod_path.begins_with("event:/"):
|
||
|
icon = _event_icon
|
||
|
elif fmod_path.begins_with("vca:/"):
|
||
|
icon = _vca_icon
|
||
|
elif fmod_path.begins_with("snapshot:/"):
|
||
|
icon = _snapshot_icon
|
||
|
return icon
|
||
|
|
||
|
static func sort_by_path(a, b):
|
||
|
return a.get_path().casecmp_to(b.get_path()) < 0
|