Full Code of utopia-rise/fmod-gdnative for AI

master a3c2dc9a72b0 cached
560 files
21.7 MB
323.4k tokens
126 symbols
1 requests
Download .txt
Showing preview only (1,304K chars total). Download the full file or copy to clipboard to get everything.
Repository: utopia-rise/fmod-gdnative
Branch: master
Commit: a3c2dc9a72b0
Files: 560
Total size: 21.7 MB

Directory structure:
gitextract_oki6utj3/

├── .clang-format
├── .gitattributes
├── .github/
│   ├── actions/
│   │   ├── create-android-plugin/
│   │   │   └── action.yaml
│   │   └── create-native-build/
│   │       └── action.yaml
│   └── workflows/
│       ├── check_pr.yml
│       └── release.yml
├── .gitignore
├── .gitmodules
├── .readthedocs.yml
├── Android.mk
├── LICENSE
├── README.md
├── SConstruct
├── android-plugin/
│   ├── .gitignore
│   ├── build.gradle.kts
│   ├── gradle/
│   │   └── wrapper/
│   │       ├── gradle-wrapper.jar
│   │       └── gradle-wrapper.properties
│   ├── gradle.properties
│   ├── gradlew
│   ├── gradlew.bat
│   ├── library/
│   │   ├── .gitignore
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       └── main/
│   │           ├── AndroidManifest.xml
│   │           ├── kotlin/
│   │           │   └── com/
│   │           │       └── utopiarise/
│   │           │           └── godot/
│   │           │               └── fmod/
│   │           │                   └── android/
│   │           │                       └── plugin/
│   │           │                           └── FmodPlugin.kt
│   │           └── resources/
│   │               └── fmod-android-license.txt
│   └── settings.gradle.kts
├── demo/
│   ├── .gitattributes
│   ├── .gitignore
│   ├── .gutconfig.json
│   ├── addons/
│   │   ├── fmod/
│   │   │   ├── .gitignore
│   │   │   ├── FmodAndroidExportPlugin.gd
│   │   │   ├── FmodAndroidExportPlugin.gd.uid
│   │   │   ├── FmodManager.gd
│   │   │   ├── FmodManager.gd.uid
│   │   │   ├── FmodPlugin.gd
│   │   │   ├── FmodPlugin.gd.uid
│   │   │   ├── fmod.gdextension
│   │   │   ├── fmod.gdextension.uid
│   │   │   ├── icons/
│   │   │   │   ├── bank_icon.svg.import
│   │   │   │   ├── bus_icon.svg.import
│   │   │   │   ├── c_parameter_icon.svg.import
│   │   │   │   ├── d_parameter_icon.svg.import
│   │   │   │   ├── event_icon.svg.import
│   │   │   │   ├── fmod_emitter.png.import
│   │   │   │   ├── fmod_icon.svg.import
│   │   │   │   ├── snapshot_icon.svg.import
│   │   │   │   └── vca_icon.svg.import
│   │   │   ├── libs/
│   │   │   │   ├── android/
│   │   │   │   │   └── arm64/
│   │   │   │   │       └── CopyPast_Fmod_Libs_Here.txt
│   │   │   │   ├── iOS/
│   │   │   │   │   └── CopyPast_Fmod_Libs_Here.txt
│   │   │   │   ├── linux/
│   │   │   │   │   └── CopyPast_Fmod_Libs_Here.txt
│   │   │   │   ├── macos/
│   │   │   │   │   ├── CopyPast_Fmod_Libs_Here.txt
│   │   │   │   │   ├── libGodotFmod.macos.editor.framework/
│   │   │   │   │   │   └── Info.plist
│   │   │   │   │   ├── libGodotFmod.macos.template_debug.framework/
│   │   │   │   │   │   └── Info.plist
│   │   │   │   │   └── libGodotFmod.macos.template_release.framework/
│   │   │   │   │       └── Info.plist
│   │   │   │   └── windows/
│   │   │   │       └── CopyPast_Fmod_Libs_Here.txt
│   │   │   ├── plugin.cfg
│   │   │   └── tool/
│   │   │       ├── FmodBankDatabase.gd
│   │   │       ├── FmodBankDatabase.gd.uid
│   │   │       ├── inspectors/
│   │   │       │   ├── FmodBankLoaderPropertyInspectorPlugin.gd
│   │   │       │   ├── FmodBankLoaderPropertyInspectorPlugin.gd.uid
│   │   │       │   ├── FmodEmitterPropertyInspectorPlugin.gd
│   │   │       │   └── FmodEmitterPropertyInspectorPlugin.gd.uid
│   │   │       ├── performances/
│   │   │       │   ├── PerformancesDisplay.gd
│   │   │       │   └── PerformancesDisplay.gd.uid
│   │   │       ├── property_editors/
│   │   │       │   ├── FmodBankPathEditorProperty.gd
│   │   │       │   ├── FmodBankPathEditorProperty.gd.uid
│   │   │       │   ├── FmodBankPathsPropertyEditorUi.tscn
│   │   │       │   ├── FmodEventEditorProperty.gd
│   │   │       │   ├── FmodEventEditorProperty.gd.uid
│   │   │       │   ├── FmodEventEditorProperty.tscn
│   │   │       │   ├── FmodGuidAndPathPropertyEditorUi.gd
│   │   │       │   ├── FmodGuidAndPathPropertyEditorUi.gd.uid
│   │   │       │   ├── FmodGuidAndPathPropertyEditorUi.tscn
│   │   │       │   ├── FmodPathEditorProperty.gd
│   │   │       │   ├── FmodPathEditorProperty.gd.uid
│   │   │       │   └── FmodPathEditorProperty.tscn
│   │   │       └── ui/
│   │   │           ├── EventParametersDisplay.gd
│   │   │           ├── EventParametersDisplay.gd.uid
│   │   │           ├── EventParametersDisplay.tscn
│   │   │           ├── EventParametersWindow.tscn
│   │   │           ├── EventPlayControls.gd
│   │   │           ├── EventPlayControls.gd.uid
│   │   │           ├── FmodBankExplorer.gd
│   │   │           ├── FmodBankExplorer.gd.uid
│   │   │           ├── FmodBankExplorer.tscn
│   │   │           ├── ParameterDisplay.gd
│   │   │           ├── ParameterDisplay.gd.uid
│   │   │           ├── ParameterDisplay.tscn
│   │   │           └── TestFmodBankExplorer.tscn
│   │   └── gut/
│   │       ├── GutScene.gd
│   │       ├── GutScene.gd.uid
│   │       ├── GutScene.tscn
│   │       ├── LICENSE.md
│   │       ├── UserFileViewer.gd
│   │       ├── UserFileViewer.gd.uid
│   │       ├── UserFileViewer.tscn
│   │       ├── autofree.gd
│   │       ├── autofree.gd.uid
│   │       ├── awaiter.gd
│   │       ├── awaiter.gd.uid
│   │       ├── cli/
│   │       │   ├── change_project_warnings.gd
│   │       │   ├── change_project_warnings.gd.uid
│   │       │   ├── gut_cli.gd
│   │       │   ├── gut_cli.gd.uid
│   │       │   ├── optparse.gd
│   │       │   └── optparse.gd.uid
│   │       ├── collected_script.gd
│   │       ├── collected_script.gd.uid
│   │       ├── collected_test.gd
│   │       ├── collected_test.gd.uid
│   │       ├── comparator.gd
│   │       ├── comparator.gd.uid
│   │       ├── compare_result.gd
│   │       ├── compare_result.gd.uid
│   │       ├── diff_formatter.gd
│   │       ├── diff_formatter.gd.uid
│   │       ├── diff_tool.gd
│   │       ├── diff_tool.gd.uid
│   │       ├── double_templates/
│   │       │   ├── function_template.txt
│   │       │   ├── init_template.txt
│   │       │   └── script_template.txt
│   │       ├── double_tools.gd
│   │       ├── double_tools.gd.uid
│   │       ├── doubler.gd
│   │       ├── doubler.gd.uid
│   │       ├── dynamic_gdscript.gd
│   │       ├── dynamic_gdscript.gd.uid
│   │       ├── editor_caret_context_notifier.gd
│   │       ├── editor_caret_context_notifier.gd.uid
│   │       ├── error_tracker.gd
│   │       ├── error_tracker.gd.uid
│   │       ├── fonts/
│   │       │   └── OFL.txt
│   │       ├── gui/
│   │       │   ├── EditorRadioButton.tres
│   │       │   ├── GutBottomPanel.gd
│   │       │   ├── GutBottomPanel.gd.uid
│   │       │   ├── GutBottomPanel.tscn
│   │       │   ├── GutControl.gd
│   │       │   ├── GutControl.gd.uid
│   │       │   ├── GutControl.tscn
│   │       │   ├── GutEditorWindow.gd
│   │       │   ├── GutEditorWindow.gd.uid
│   │       │   ├── GutEditorWindow.tscn
│   │       │   ├── GutLogo.tscn
│   │       │   ├── GutRunner.gd
│   │       │   ├── GutRunner.gd.uid
│   │       │   ├── GutRunner.tscn
│   │       │   ├── GutSceneTheme.tres
│   │       │   ├── MinGui.tscn
│   │       │   ├── NormalGui.tscn
│   │       │   ├── OutputText.gd
│   │       │   ├── OutputText.gd.uid
│   │       │   ├── OutputText.tscn
│   │       │   ├── ResizeHandle.gd
│   │       │   ├── ResizeHandle.gd.uid
│   │       │   ├── ResizeHandle.tscn
│   │       │   ├── ResultsTree.gd
│   │       │   ├── ResultsTree.gd.uid
│   │       │   ├── ResultsTree.tscn
│   │       │   ├── RunAtCursor.gd
│   │       │   ├── RunAtCursor.gd.uid
│   │       │   ├── RunAtCursor.tscn
│   │       │   ├── RunExternally.gd
│   │       │   ├── RunExternally.gd.uid
│   │       │   ├── RunExternally.tscn
│   │       │   ├── RunResults.gd
│   │       │   ├── RunResults.gd.uid
│   │       │   ├── RunResults.tscn
│   │       │   ├── Settings.tscn
│   │       │   ├── ShellOutOptions.gd
│   │       │   ├── ShellOutOptions.gd.uid
│   │       │   ├── ShellOutOptions.tscn
│   │       │   ├── ShortcutButton.gd
│   │       │   ├── ShortcutButton.gd.uid
│   │       │   ├── ShortcutButton.tscn
│   │       │   ├── ShortcutDialog.gd
│   │       │   ├── ShortcutDialog.gd.uid
│   │       │   ├── ShortcutDialog.tscn
│   │       │   ├── about.gd
│   │       │   ├── about.gd.uid
│   │       │   ├── about.tscn
│   │       │   ├── editor_globals.gd
│   │       │   ├── editor_globals.gd.uid
│   │       │   ├── gut_config_gui.gd
│   │       │   ├── gut_config_gui.gd.uid
│   │       │   ├── gut_gui.gd
│   │       │   ├── gut_gui.gd.uid
│   │       │   ├── gut_logo.gd
│   │       │   ├── gut_logo.gd.uid
│   │       │   ├── gut_user_preferences.gd
│   │       │   ├── gut_user_preferences.gd.uid
│   │       │   ├── option_maker.gd
│   │       │   ├── option_maker.gd.uid
│   │       │   ├── panel_controls.gd
│   │       │   ├── panel_controls.gd.uid
│   │       │   ├── run_from_editor.gd
│   │       │   ├── run_from_editor.gd.uid
│   │       │   └── run_from_editor.tscn
│   │       ├── gut.gd
│   │       ├── gut.gd.uid
│   │       ├── gut_cmdln.gd
│   │       ├── gut_cmdln.gd.uid
│   │       ├── gut_config.gd
│   │       ├── gut_config.gd.uid
│   │       ├── gut_fonts.gd
│   │       ├── gut_fonts.gd.uid
│   │       ├── gut_loader.gd
│   │       ├── gut_loader.gd.uid
│   │       ├── gut_loader_the_scene.tscn
│   │       ├── gut_menu.gd
│   │       ├── gut_menu.gd.uid
│   │       ├── gut_plugin.gd
│   │       ├── gut_plugin.gd.uid
│   │       ├── gut_to_move.gd
│   │       ├── gut_to_move.gd.uid
│   │       ├── gut_tracked_error.gd
│   │       ├── gut_tracked_error.gd.uid
│   │       ├── gut_vscode_debugger.gd
│   │       ├── gut_vscode_debugger.gd.uid
│   │       ├── hook_script.gd
│   │       ├── hook_script.gd.uid
│   │       ├── inner_class_registry.gd
│   │       ├── inner_class_registry.gd.uid
│   │       ├── input_factory.gd
│   │       ├── input_factory.gd.uid
│   │       ├── input_sender.gd
│   │       ├── input_sender.gd.uid
│   │       ├── junit_xml_export.gd
│   │       ├── junit_xml_export.gd.uid
│   │       ├── lazy_loader.gd
│   │       ├── lazy_loader.gd.uid
│   │       ├── logger.gd
│   │       ├── logger.gd.uid
│   │       ├── menu_manager.gd.uid
│   │       ├── method_maker.gd
│   │       ├── method_maker.gd.uid
│   │       ├── one_to_many.gd
│   │       ├── one_to_many.gd.uid
│   │       ├── orphan_counter.gd
│   │       ├── orphan_counter.gd.uid
│   │       ├── parameter_factory.gd
│   │       ├── parameter_factory.gd.uid
│   │       ├── parameter_handler.gd
│   │       ├── parameter_handler.gd.uid
│   │       ├── plugin.cfg
│   │       ├── printers.gd
│   │       ├── printers.gd.uid
│   │       ├── result_exporter.gd
│   │       ├── result_exporter.gd.uid
│   │       ├── script_parser.gd
│   │       ├── script_parser.gd.uid
│   │       ├── signal_watcher.gd
│   │       ├── signal_watcher.gd.uid
│   │       ├── source_code_pro.fnt
│   │       ├── spy.gd
│   │       ├── spy.gd.uid
│   │       ├── strutils.gd
│   │       ├── strutils.gd.uid
│   │       ├── stub_params.gd
│   │       ├── stub_params.gd.uid
│   │       ├── stubber.gd
│   │       ├── stubber.gd.uid
│   │       ├── summary.gd
│   │       ├── summary.gd.uid
│   │       ├── test.gd
│   │       ├── test.gd.uid
│   │       ├── test_collector.gd
│   │       ├── test_collector.gd.uid
│   │       ├── thing_counter.gd
│   │       ├── thing_counter.gd.uid
│   │       ├── utils.gd
│   │       ├── utils.gd.uid
│   │       ├── version_conversion.gd
│   │       ├── version_conversion.gd.uid
│   │       ├── version_numbers.gd
│   │       ├── version_numbers.gd.uid
│   │       ├── warnings_manager.gd
│   │       └── warnings_manager.gd.uid
│   ├── appstore.png.import
│   ├── assets/
│   │   ├── Banks/
│   │   │   ├── Dialogue_CN.bank
│   │   │   ├── Dialogue_EN.bank
│   │   │   ├── Dialogue_JP.bank
│   │   │   ├── Master.bank
│   │   │   ├── Master.strings.bank
│   │   │   ├── Music.bank
│   │   │   ├── SFX.bank
│   │   │   └── Vehicles.bank
│   │   ├── Music/
│   │   │   ├── License.txt
│   │   │   ├── jingles_SAX07.ogg
│   │   │   └── jingles_SAX07.ogg.import
│   │   └── Sounds/
│   │       ├── beltHandle1.ogg
│   │       ├── beltHandle1.ogg.import
│   │       ├── beltHandle2.ogg
│   │       ├── beltHandle2.ogg.import
│   │       ├── bookClose.ogg
│   │       ├── bookClose.ogg.import
│   │       ├── bookFlip1.ogg
│   │       ├── bookFlip1.ogg.import
│   │       ├── bookFlip2.ogg
│   │       ├── bookFlip2.ogg.import
│   │       ├── bookFlip3.ogg
│   │       ├── bookFlip3.ogg.import
│   │       ├── bookOpen.ogg
│   │       ├── bookOpen.ogg.import
│   │       ├── bookPlace1.ogg
│   │       ├── bookPlace1.ogg.import
│   │       ├── bookPlace2.ogg
│   │       ├── bookPlace2.ogg.import
│   │       ├── bookPlace3.ogg
│   │       ├── bookPlace3.ogg.import
│   │       ├── chop.ogg
│   │       ├── chop.ogg.import
│   │       ├── cloth1.ogg
│   │       ├── cloth1.ogg.import
│   │       ├── cloth2.ogg
│   │       ├── cloth2.ogg.import
│   │       ├── cloth3.ogg
│   │       ├── cloth3.ogg.import
│   │       ├── cloth4.ogg
│   │       ├── cloth4.ogg.import
│   │       ├── clothBelt.ogg
│   │       ├── clothBelt.ogg.import
│   │       ├── clothBelt2.ogg
│   │       ├── clothBelt2.ogg.import
│   │       ├── creak1.ogg
│   │       ├── creak1.ogg.import
│   │       ├── creak2.ogg
│   │       ├── creak2.ogg.import
│   │       ├── creak3.ogg
│   │       ├── creak3.ogg.import
│   │       ├── doorClose_1.ogg
│   │       ├── doorClose_1.ogg.import
│   │       ├── doorClose_2.ogg
│   │       ├── doorClose_2.ogg.import
│   │       ├── doorClose_3.ogg
│   │       ├── doorClose_3.ogg.import
│   │       ├── doorClose_4.ogg
│   │       ├── doorClose_4.ogg.import
│   │       ├── doorOpen_1.ogg
│   │       ├── doorOpen_1.ogg.import
│   │       ├── doorOpen_2.ogg
│   │       ├── doorOpen_2.ogg.import
│   │       ├── drawKnife1.ogg
│   │       ├── drawKnife1.ogg.import
│   │       ├── drawKnife2.ogg
│   │       ├── drawKnife2.ogg.import
│   │       ├── drawKnife3.ogg
│   │       ├── drawKnife3.ogg.import
│   │       ├── dropLeather.ogg
│   │       ├── dropLeather.ogg.import
│   │       ├── footstep00.ogg
│   │       ├── footstep00.ogg.import
│   │       ├── footstep01.ogg
│   │       ├── footstep01.ogg.import
│   │       ├── footstep02.ogg
│   │       ├── footstep02.ogg.import
│   │       ├── footstep03.ogg
│   │       ├── footstep03.ogg.import
│   │       ├── footstep04.ogg
│   │       ├── footstep04.ogg.import
│   │       ├── footstep05.ogg
│   │       ├── footstep05.ogg.import
│   │       ├── footstep06.ogg
│   │       ├── footstep06.ogg.import
│   │       ├── footstep07.ogg
│   │       ├── footstep07.ogg.import
│   │       ├── footstep08.ogg
│   │       ├── footstep08.ogg.import
│   │       ├── footstep09.ogg
│   │       ├── footstep09.ogg.import
│   │       ├── handleCoins.ogg
│   │       ├── handleCoins.ogg.import
│   │       ├── handleCoins2.ogg
│   │       ├── handleCoins2.ogg.import
│   │       ├── handleSmallLeather.ogg
│   │       ├── handleSmallLeather.ogg.import
│   │       ├── handleSmallLeather2.ogg
│   │       ├── handleSmallLeather2.ogg.import
│   │       ├── knifeSlice.ogg
│   │       ├── knifeSlice.ogg.import
│   │       ├── knifeSlice2.ogg
│   │       ├── knifeSlice2.ogg.import
│   │       ├── licence.txt
│   │       ├── metalClick.ogg
│   │       ├── metalClick.ogg.import
│   │       ├── metalLatch.ogg
│   │       ├── metalLatch.ogg.import
│   │       ├── metalPot1.ogg
│   │       ├── metalPot1.ogg.import
│   │       ├── metalPot2.ogg
│   │       ├── metalPot2.ogg.import
│   │       ├── metalPot3.ogg
│   │       └── metalPot3.ogg.import
│   ├── default_env.tres
│   ├── export_presets.cfg
│   ├── high_level_2D/
│   │   ├── ChangeColor.gd
│   │   ├── ChangeColor.gd.uid
│   │   ├── ChooseLanguageButton.gd
│   │   ├── ChooseLanguageButton.gd.uid
│   │   ├── Emitter.gd
│   │   ├── Emitter.gd.uid
│   │   ├── FmodNodesTest.tscn
│   │   ├── Kinematic.gd
│   │   ├── Kinematic.gd.uid
│   │   ├── SayWelcomeButton.gd
│   │   ├── SayWelcomeButton.gd.uid
│   │   ├── footstep.tscn
│   │   ├── sin_move.gd
│   │   └── sin_move.gd.uid
│   ├── high_level_3D/
│   │   ├── FPSCounter.gd
│   │   ├── FPSCounter.gd.uid
│   │   ├── World.tscn
│   │   ├── environment/
│   │   │   ├── 1x1.png.import
│   │   │   ├── Ball.tscn
│   │   │   ├── Floor.tscn
│   │   │   ├── Wall.tscn
│   │   │   ├── ball_material.tres
│   │   │   ├── box.tscn
│   │   │   ├── sin_move.gd
│   │   │   ├── sin_move.gd.uid
│   │   │   ├── soundcollider.gd
│   │   │   ├── soundcollider.gd.uid
│   │   │   └── wall_material.tres
│   │   ├── player/
│   │   │   ├── Camera.gd
│   │   │   ├── Camera.gd.uid
│   │   │   ├── Player.gd
│   │   │   ├── Player.gd.uid
│   │   │   └── Player.tscn
│   │   ├── rollingball.gd
│   │   ├── rollingball.gd.uid
│   │   ├── selfdestroy.gd
│   │   └── selfdestroy.gd.uid
│   ├── icon.png.import
│   ├── icon.svg.import
│   ├── low_level_2D/
│   │   ├── ChangeColor.gd
│   │   ├── ChangeColor.gd.uid
│   │   ├── Emitter.gd
│   │   ├── Emitter.gd.uid
│   │   ├── EnterAndLeave.gd
│   │   ├── EnterAndLeave.gd.uid
│   │   ├── EnterandLeave2.gd
│   │   ├── EnterandLeave2.gd.uid
│   │   ├── FmodScriptTest.tscn
│   │   ├── FmodTest.gd
│   │   ├── FmodTest.gd.uid
│   │   ├── LangChooseButton.gd
│   │   ├── LangChooseButton.gd.uid
│   │   ├── Listener.gd
│   │   ├── Listener.gd.uid
│   │   ├── Listener2.gd
│   │   ├── Listener2.gd.uid
│   │   ├── WelcomeButton.gd
│   │   └── WelcomeButton.gd.uid
│   ├── project.godot
│   ├── run_tests.sh
│   └── test/
│       ├── integration/
│       │   └── init
│       ├── tests.tscn
│       └── unit/
│           ├── test_bank.gd
│           ├── test_bank.gd.uid
│           ├── test_bus.gd
│           ├── test_bus.gd.uid
│           ├── test_callbacks.gd
│           ├── test_callbacks.gd.uid
│           ├── test_desc_event.gd
│           ├── test_desc_event.gd.uid
│           ├── test_event.gd
│           ├── test_event.gd.uid
│           ├── test_global.gd
│           ├── test_global.gd.uid
│           ├── test_listener.gd
│           ├── test_listener.gd.uid
│           ├── test_sound.gd
│           ├── test_sound.gd.uid
│           ├── test_vca.gd
│           └── test_vca.gd.uid
├── docs/
│   ├── .gitignore
│   ├── build.sh
│   ├── mkdocs.yml
│   ├── requirements.txt
│   ├── run.sh
│   └── src/
│       └── doc/
│           ├── advanced/
│           │   └── 1-compiling.md
│           ├── index.md
│           └── user-guide/
│               ├── 1-install.md
│               ├── 2-initialization.md
│               ├── 3-using-fmod-plugin.md
│               ├── 4-loading-banks.md
│               ├── 5-playing-events.md
│               ├── 6-listeners.md
│               ├── 7-playing-sounds.md
│               ├── 8-other-low-level-examples.md
│               └── 9-plugins.md
├── get_fmod.py
├── jni/
│   └── Application.mk
└── src/
    ├── callback/
    │   ├── event_callbacks.cpp
    │   ├── event_callbacks.h
    │   ├── file_callbacks.cpp
    │   └── file_callbacks.h
    ├── constants.h
    ├── core/
    │   ├── fmod_file.cpp
    │   ├── fmod_file.h
    │   ├── fmod_sound.cpp
    │   └── fmod_sound.h
    ├── data/
    │   ├── performance_data.cpp
    │   └── performance_data.h
    ├── fmod_cache.cpp
    ├── fmod_cache.h
    ├── fmod_logging.cpp
    ├── fmod_logging.h
    ├── fmod_server.cpp
    ├── fmod_server.h
    ├── fmod_string_names.cpp
    ├── fmod_string_names.h
    ├── helpers/
    │   ├── common.h
    │   ├── constants.h
    │   ├── current_function.h
    │   ├── files.h
    │   └── maths.h
    ├── nodes/
    │   ├── fmod_bank_loader.cpp
    │   ├── fmod_bank_loader.h
    │   ├── fmod_event_emitter.h
    │   ├── fmod_event_emitter_2d.cpp
    │   ├── fmod_event_emitter_2d.h
    │   ├── fmod_event_emitter_3d.cpp
    │   ├── fmod_event_emitter_3d.h
    │   ├── fmod_listener.h
    │   ├── fmod_listener_2d.cpp
    │   ├── fmod_listener_2d.h
    │   ├── fmod_listener_3d.cpp
    │   └── fmod_listener_3d.h
    ├── plugins/
    │   ├── ios_plugins_loader.h
    │   └── plugins_helper.h
    ├── register_types.cpp
    ├── register_types.h
    ├── resources/
    │   ├── fmod_dsp_settings.cpp
    │   ├── fmod_dsp_settings.h
    │   ├── fmod_logging_settings.cpp
    │   ├── fmod_logging_settings.h
    │   ├── fmod_plugins_settings.cpp
    │   ├── fmod_plugins_settings.h
    │   ├── fmod_settings.cpp
    │   ├── fmod_settings.h
    │   ├── fmod_software_format_settings.cpp
    │   ├── fmod_software_format_settings.h
    │   ├── fmod_sound_3d_settings.cpp
    │   └── fmod_sound_3d_settings.h
    ├── studio/
    │   ├── fmod_bank.cpp
    │   ├── fmod_bank.h
    │   ├── fmod_bus.cpp
    │   ├── fmod_bus.h
    │   ├── fmod_event.cpp
    │   ├── fmod_event.h
    │   ├── fmod_event_description.cpp
    │   ├── fmod_event_description.h
    │   ├── fmod_parameter_description.cpp
    │   ├── fmod_parameter_description.h
    │   ├── fmod_vca.cpp
    │   └── fmod_vca.h
    └── tools/
        ├── fmod_editor_export_plugin.cpp
        ├── fmod_editor_export_plugin.h
        ├── fmod_editor_plugin.cpp
        └── fmod_editor_plugin.h

================================================
FILE CONTENTS
================================================

================================================
FILE: .clang-format
================================================
---
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: BlockIndent
AlignEscapedNewlines: Left
AlignOperands: AlignAfterOperator
AlignTrailingComments: false

#Allow
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: Always
AllowShortLambdasOnASingleLine: All
AllowShortEnumsOnASingleLine: false

AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes

BinPackArguments: false
BinPackParameters: false

#Brace`
BreakBeforeBraces: Custom
BraceWrapping:
  AfterCaseLabel: false
  AfterClass: false
  AfterControlStatement: Never
  AfterEnum: false
  AfterFunction: false
  AfterNamespace: false
  AfterStruct: false
  AfterUnion: false
  AfterExternBlock: false
  BeforeCatch: false
  BeforeElse: false
  BeforeWhile: false
  IndentBraces: false
  SplitEmptyFunction: false
  SplitEmptyRecord: false
  SplitEmptyNamespace: false

BreakBeforeBinaryOperators: NonAssignment
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
BreakInheritanceList: AfterComma
BreakStringLiterals: true
ColumnLimit: 120
CompactNamespaces: false
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: Always
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
IncludeBlocks: Regroup
IncludeCategories:
  - Regex: '".*"'
    Priority: 1
  - Regex: '^<.*\.h>'
    Priority: 2
  - Regex: '^<.*'
    Priority: 3
IndentAccessModifiers: false
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
PackConstructorInitializers: CurrentLine

#Penalty
PenaltyBreakAssignment: 40
PenaltyBreakBeforeFirstCallParameter: 0
PenaltyBreakComment: 100
PenaltyBreakFirstLessLess: 0
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 100
PenaltyBreakTemplateDeclaration: 0
PenaltyExcessCharacter: 1
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 10000

PointerAlignment: Left
ReferenceAlignment: Left
ReflowComments: true
SeparateDefinitionBlocks: Always
ShortNamespaceLines: 0
SortIncludes: CaseInsensitive
SortUsingDeclarations: false

#Space
SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 0
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInLineCommentPrefix:
  Minimum: 1
  Maximum: 1
SpacesInParentheses: false
SpacesInSquareBrackets: false

#Tab
TabWidth: 4
UseTab: Never
---
Language: Cpp
Standard: c++17
...


================================================
FILE: .gitattributes
================================================
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf

# Ignore some files when exporting to a ZIP.
# Only include the addons folder when downloading from the Asset Library.
/**                  export-ignore
/addons/fmod         !export-ignore
/addons/fmod/**      !export-ignore

================================================
FILE: .github/actions/create-android-plugin/action.yaml
================================================
name: Create Fmod native build
description: Creates fmod native build for a specific platform
runs:
  using: composite
  steps:
    - name: Set up JDK 17
      uses: actions/setup-java@v1
      with:
        java-version: 17

    - name: Download fmod jar
      uses: actions/download-artifact@v4
      with:
        name: fmod-jar
        path: android-plugin/library/libraries/

    - name: Build android plugin
      uses: eskatos/gradle-command-action@v1
      with:
        wrapper-directory: android-plugin/
        build-root-directory: android-plugin/
        arguments: :library:build

================================================
FILE: .github/actions/create-native-build/action.yaml
================================================
name: Create Fmod native build
description: Creates fmod native build for a specific platform
inputs:
  platform:
    description: The platform to build for.
  target:
    description: The target to build.
  additional-python-packages:
    description: Additional python package to install.
  flags:
    description: Additional compilation scons flags.
  fmod-executable-suffix:
    description: The suffix of fmod executable to install fmod libraries.
  fmod-user:
    description: The FMOD user used to download fmod binaries
  fmod-password:
    description: The password for fmod account used to download fmod binaries.
  shell:
    description: The shell used by the runner.
runs:
  using: composite
  steps:
    # Use python 3.x release (works cross platform; best to keep self contained in it's own step)
    - name: Set up Python 3.x
      uses: actions/setup-python@v4
      with:
        # Semantic version range syntax or exact version of a Python version
        python-version: "3.x"
        # Optional - x64 or x86 architecture, defaults to x64
        architecture: "x64"

    # Setup scons, print python version and scons version info, so if anything is broken it won't run the build.
    #TODO: remove hardcoded scons version when https://github.com/godotengine/godot-cpp/pull/1526 is released
    - name: Configuring Python packages
      shell: ${{ inputs.shell }}
      run: |
        python -c "import sys; print(sys.version)"
        python -m pip install scons==4.7.0 requests ${{ inputs.additional-python-packages }}
        python --version
        scons --version

    - name: Installing FMOD on Windows
      shell: ${{ inputs.shell }}
      if: runner.os == 'Windows'
      run: |
        cd ..
        New-Item -ItemType directory -Path libs; cd libs
        New-Item -ItemType directory -Path fmod; cd fmod
        python ../../fmod-gdextension/get_fmod.py ${{inputs.fmod-user}} ${{inputs.fmod-password}} ${{inputs.platform}} ${{env.FMOD_VERSION}}
        7z x fmodstudioapi${{env.FMOD_VERSION}}${{inputs.fmod-executable-suffix}}
        ls
        mv api/ windows
        cd ../../

    - name: Installing FMOD on Linux & Android
      if: runner.os == 'Linux'
      shell: ${{ inputs.shell }}
      run: |
        cd ..
        mkdir libs && cd libs
        mkdir fmod && cd fmod
        python ../../fmod-gdextension/get_fmod.py ${{inputs.fmod-user}} ${{inputs.fmod-password}} ${{inputs.platform}} ${{env.FMOD_VERSION}}
        tar -xvf fmodstudioapi${{env.FMOD_VERSION}}${{inputs.fmod-executable-suffix}}
        mv fmodstudioapi${{env.FMOD_VERSION}}${{inputs.platform}}/api ${{inputs.platform}}
        cd ../../

    - name: Installing FMOD on MacOS & iOS
      if: runner.os == 'MacOS'
      shell: ${{ inputs.shell }}
      run: |
        cd ..
        mkdir libs && cd libs
        mkdir fmod && cd fmod
        python ../../fmod-gdextension/get_fmod.py ${{inputs.fmod-user}} ${{inputs.fmod-password}} ${{inputs.platform}} ${{env.FMOD_VERSION}}
        hdiutil attach fmodstudioapi${{env.FMOD_VERSION}}${{inputs.fmod-executable-suffix}}
        [[ ${{inputs.platform}} = "macos" ]] && cp -r "/Volumes/FMOD Programmers API Mac/FMOD Programmers API/api" osx
        [[ ${{inputs.platform}} = "ios" ]] && cp -r "/Volumes/FMOD Programmers API iOS/FMOD Programmers API/api" ios
        cd ../../

    - name: create android fmod artifact
      if: inputs.platform == 'android' && inputs.target == 'template_release'
      shell: ${{ inputs.shell }}
      run: |
        mkdir android-fmod-artifact
        cp ../libs/fmod/android/core/lib/fmod.jar android-fmod-artifact/
        cp android-plugin/library/src/main/resources/fmod-android-license.txt android-fmod-artifact/

    - name: Upload fmod jar
      if: inputs.platform == 'android' && inputs.target == 'template_release'
      uses: actions/upload-artifact@v4
      with:
        name: fmod-jar
        path: android-fmod-artifact
        if-no-files-found: error

    - name: Get number of CPU cores
      id: cpu-cores
      uses: SimenB/github-actions-cpu-cores@v1

    - name: Compilation
      shell: ${{ inputs.shell }}
      run: |
        cd ../fmod-gdextension
        scons platform=${{ inputs.platform }} generate_bindings=yes target=${{ inputs.target }} target_path=${{ env.TARGET_PATH }} target_name=${{ env.TARGET_NAME }} -j${{ steps.cpu-cores.outputs.count }} ${{ inputs.flags }}

    - name: Upload Artifact
      uses: actions/upload-artifact@v4
      with:
        name: ${{ inputs.platform }}-${{ inputs.target }}
        path: ${{ env.TARGET_PATH }}${{ inputs.platform }}/**/*.*
        if-no-files-found: error


================================================
FILE: .github/workflows/check_pr.yml
================================================
name: 🌈 Check Pull Request
on:
  pull_request:
    types: [opened, synchronize, reopened]
  pull_request_target:
    types: [opened, synchronize, reopened]

# Global Settings
env:
  GODOT_VERSION: 4.5
  NDK_VERSION: 27.3.13750724
  TARGET_PATH: demo/addons/fmod/libs/
  TARGET_NAME: libGodotFmod
  FMOD_VERSION: 20306
jobs:
  gate:
    runs-on: ubuntu-latest
    # EXCLUSIVE PATHS:
    # - In-repo PRs use pull_request
    # - External PRs use pull_request_target, so secrets are available, but only after the run is approved
    if: >
      (
        github.event_name == 'pull_request' &&
        github.event.pull_request.head.repo.full_name == github.repository
      ) || (
        github.event_name == 'pull_request_target' &&
        github.event.pull_request.head.repo.full_name != github.repository
      )
    environment: ${{ github.event_name == 'pull_request_target' && 'external-pr' || '' }}
    steps:
      - run: echo "Run Approved"

  build:
    name: ${{ matrix.name }}
    needs: gate
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: Windows Editor Compilation
            os: "windows-2022"
            platform: windows
            target: editor
            additional-python-packages: pywin32
            fmod-executable-suffix: win-installer.exe
            shell: pwsh

          - name: Windows Debug Compilation
            os: "windows-2022"
            platform: windows
            target: template_debug
            additional-python-packages: pywin32
            fmod-executable-suffix: win-installer.exe
            shell: pwsh

          - name: Windows Release Compilation
            os: "windows-2022"
            platform: windows
            target: template_release
            additional-python-packages: pywin32
            fmod-executable-suffix: win-installer.exe
            shell: pwsh

          - name: Ubuntu Editor Compilation
            os: "ubuntu-22.04"
            platform: linux
            target: editor
            fmod-executable-suffix: linux.tar.gz
            fmod-core-platform-folder: linux/core/lib/x86_64
            fmod-studio-platform-folder: linux/studio/lib/x86_64
            fmod-library-suffix: so
            godot-executable-download-suffix: linux.x86_64.zip
            godot-executable: Godot_v$GODOT_VERSION-stable_linux.x86_64
            shell: bash

          - name: Ubuntu Debug Compilation
            os: "ubuntu-22.04"
            platform: linux
            target: template_debug
            fmod-executable-suffix: linux.tar.gz
            shell: bash

          - name: Ubuntu Release Compilation
            os: "ubuntu-22.04"
            platform: linux
            target: template_release
            fmod-executable-suffix: linux.tar.gz
            shell: bash

          - name: MacOS Editor Compilation
            os: "macos-14"
            platform: macos
            target: editor
            fmod-executable-suffix: osx.dmg
            fmod-core-platform-folder: osx/core/lib
            fmod-studio-platform-folder: osx/studio/lib
            fmod-library-suffix: dylib
            godot-executable-download-suffix: macos.universal.zip
            godot-executable: Godot.app/Contents/MacOs/Godot
            shell: bash

          - name: MacOS Debug Compilation
            os: "macos-14"
            platform: macos
            target: template_debug
            fmod-executable-suffix: osx.dmg
            shell: bash

          - name: MacOS Release Compilation
            os: "macos-14"
            platform: macos
            target: template_release
            fmod-executable-suffix: osx.dmg
            shell: bash

          - name: Android Editor Compilation
            os: "ubuntu-22.04"
            platform: android
            target: editor
            fmod-executable-suffix: android.tar.gz
            flags: ndk_version=$NDK_VERSION arch=arm64
            shell: bash

          - name: Android Debug Compilation
            os: "ubuntu-22.04"
            platform: android
            target: template_debug
            fmod-executable-suffix: android.tar.gz
            flags: ndk_version=$NDK_VERSION arch=arm64
            shell: bash

          - name: Android Release Compilation
            os: "ubuntu-22.04"
            platform: android
            target: template_release
            fmod-executable-suffix: android.tar.gz
            flags: ndk_version=$NDK_VERSION arch=arm64
            shell: bash

          - name: iOS Debug Compilation
            os: "macos-14"
            platform: ios
            target: template_debug
            fmod-executable-suffix: ios.dmg
            shell: bash

          - name: iOS Release Compilation
            os: "macos-14"
            platform: ios
            target: template_release
            fmod-executable-suffix: ios.dmg
            shell: bash

    steps:
      - name: Checkout (in-repo PR)
        if: github.event_name == 'pull_request'
        uses: actions/checkout@v4
        with:
          lfs: true
          submodules: recursive

      - name: Checkout (external PR via target)
        if: github.event_name == 'pull_request_target'
        uses: actions/checkout@v4
        with:
          lfs: true
          submodules: recursive
          ref: ${{ github.event.pull_request.head.sha }}
          persist-credentials: false

      - name: Android dependencies
        if: ${{ matrix.platform == 'android' }}
        uses: nttld/setup-ndk@v1
        with:
          ndk-version: r23c
          link-to-sdk: true

      - name: Compile native plugin
        uses: ./.github/actions/create-native-build
        with:
          platform: ${{ matrix.platform }}
          target: ${{ matrix.target }}
          additional-python-packages: ${{ matrix.additional-python-packages }}
          flags: ${{ matrix.flags }}
          fmod-executable-suffix: ${{ matrix.fmod-executable-suffix }}
          fmod-user: ${{ secrets.FMODUSER }}
          fmod-password: ${{ secrets.FMODPASS }}
          shell: ${{ matrix.shell }}

      - name: Download godot engine
        if: matrix.platform != 'android' && matrix.platform != 'ios' && matrix.platform != 'windows' && matrix.target == 'editor'
        run: |
          wget https://github.com/godotengine/godot-builds/releases/download/${{env.GODOT_VERSION}}-stable/Godot_v${{env.GODOT_VERSION}}-stable_${{ matrix.godot-executable-download-suffix }}
          unzip Godot_v${{env.GODOT_VERSION}}-stable_${{ matrix.godot-executable-download-suffix }}
          rm Godot_v${{env.GODOT_VERSION}}-stable_${{ matrix.godot-executable-download-suffix }}

      - name: Run tests
        if: matrix.platform != 'android' && matrix.platform != 'ios' && matrix.platform != 'windows' && matrix.target == 'editor'
        run: |
          cd demo
          chmod +x run_tests.sh
          chmod +x ../${{ matrix.godot-executable }}
          ./run_tests.sh ../${{ matrix.godot-executable }}

  create-android-plugin:
    needs: [build]
    strategy:
      matrix:
        include:
          - os: "ubuntu-22.04"
    runs-on: ${{ matrix.os }}
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          lfs: true
          submodules: recursive

      - name: Create android plugin
        uses: ./.github/actions/create-android-plugin


================================================
FILE: .github/workflows/release.yml
================================================
name: 🌈 Release
on:
  push:
    tags:
      - '\d+.\d+.\d+-\d+.\d+.\d+'

# Global Settings
env:
  GODOT_VERSION: 4.5
  NDK_VERSION: 27.3.13750724
  TARGET_PATH: demo/addons/fmod/libs/
  TARGET_NAME: libGodotFmod
  FMOD_VERSION: 20306
jobs:
  build:
    name: ${{ matrix.name }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: Windows Editor Compilation
            os: "windows-2022"
            platform: windows
            target: editor
            additional-python-packages: pywin32
            fmod-executable-suffix: win-installer.exe
            shell: pwsh

          - name: Windows Debug Compilation
            os: "windows-2022"
            platform: windows
            target: template_debug
            additional-python-packages: pywin32
            fmod-executable-suffix: win-installer.exe
            shell: pwsh

          - name: Windows Release Compilation
            os: "windows-2022"
            platform: windows
            target: template_release
            additional-python-packages: pywin32
            fmod-executable-suffix: win-installer.exe
            shell: pwsh

          - name: Ubuntu Editor Compilation
            os: "ubuntu-22.04"
            platform: linux
            target: editor
            fmod-executable-suffix: linux.tar.gz
            fmod-core-platform-folder: linux/core/lib/x86_64
            fmod-studio-platform-folder: linux/studio/lib/x86_64
            fmod-library-suffix: so
            godot-executable-download-suffix: linux.x86_64.zip
            godot-executable: Godot_v$GODOT_VERSION-stable_linux.x86_64
            shell: bash

          - name: Ubuntu Debug Compilation
            os: "ubuntu-22.04"
            platform: linux
            target: template_debug
            fmod-executable-suffix: linux.tar.gz
            shell: bash

          - name: Ubuntu Release Compilation
            os: "ubuntu-22.04"
            platform: linux
            target: template_release
            fmod-executable-suffix: linux.tar.gz
            shell: bash

          - name: MacOS Editor Compilation
            os: "macos-14"
            platform: macos
            target: editor
            fmod-executable-suffix: osx.dmg
            fmod-core-platform-folder: osx/core/lib
            fmod-studio-platform-folder: osx/studio/lib
            fmod-library-suffix: dylib
            godot-executable-download-suffix: macos.universal.zip
            godot-executable: Godot.app/Contents/MacOs/Godot
            shell: bash

          - name: MacOS Debug Compilation
            os: "macos-14"
            platform: macos
            target: template_debug
            fmod-executable-suffix: osx.dmg
            shell: bash

          - name: MacOS Release Compilation
            os: "macos-14"
            platform: macos
            target: template_release
            fmod-executable-suffix: osx.dmg
            shell: bash

          - name: Android Editor Compilation
            os: "ubuntu-22.04"
            platform: android
            target: editor
            fmod-executable-suffix: android.tar.gz
            flags: ndk_version=$NDK_VERSION arch=arm64
            shell: bash

          - name: Android Debug Compilation
            os: "ubuntu-22.04"
            platform: android
            target: template_debug
            fmod-executable-suffix: android.tar.gz
            flags: ndk_version=$NDK_VERSION arch=arm64
            shell: bash

          - name: Android Release Compilation
            os: "ubuntu-22.04"
            platform: android
            target: template_release
            fmod-executable-suffix: android.tar.gz
            flags: ndk_version=$NDK_VERSION arch=arm64
            shell: bash

          - name: iOS Debug Compilation
            os: "macos-14"
            platform: ios
            target: template_debug
            fmod-executable-suffix: ios.dmg
            shell: bash

          - name: iOS Release Compilation
            os: "macos-14"
            platform: ios
            target: template_release
            fmod-executable-suffix: ios.dmg
            shell: bash

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          lfs: true
          submodules: recursive

      - name: Android dependencies
        if: ${{ matrix.platform == 'android' }}
        uses: nttld/setup-ndk@v1
        with:
          ndk-version: r23c
          link-to-sdk: true

      - name: Compile native plugin
        uses: ./.github/actions/create-native-build
        with:
          platform: ${{ matrix.platform }}
          target: ${{ matrix.target }}
          additional-python-packages: ${{ matrix.additional-python-packages }}
          flags: ${{ matrix.flags }}
          fmod-executable-suffix: ${{ matrix.fmod-executable-suffix }}
          fmod-user: ${{ secrets.FMODUSER }}
          fmod-password: ${{ secrets.FMODPASS }}
          shell: ${{ matrix.shell }}

  package-godot-addon:
    needs: [build]
    strategy:
      matrix:
        include:
          - os: "ubuntu-22.04"
    runs-on: ${{ matrix.os }}
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          lfs: true
          submodules: recursive

      - name: Create android plugin
        uses: ./.github/actions/create-android-plugin
        with:
          godot-version: ${{ env.GODOT_VERSION }}

      - name: Download linux editor libraries
        uses: actions/download-artifact@v4
        with:
          name: linux-editor
          path: demo/addons/fmod/libs/linux/

      - name: Download linux template_debug libraries
        uses: actions/download-artifact@v4
        with:
          name: linux-template_debug
          path: demo/addons/fmod/libs/linux/

      - name: Download linux template_release libraries
        uses: actions/download-artifact@v4
        with:
          name: linux-template_release
          path: demo/addons/fmod/libs/linux/

      - name: Download windows editor libraries
        uses: actions/download-artifact@v4
        with:
          name: windows-editor
          path: demo/addons/fmod/libs/windows/

      - name: Download windows template_debug libraries
        uses: actions/download-artifact@v4
        with:
          name: windows-template_debug
          path: demo/addons/fmod/libs/windows/

      - name: Download windows template_release libraries
        uses: actions/download-artifact@v4
        with:
          name: windows-template_release
          path: demo/addons/fmod/libs/windows/

      - name: Download macos editor libraries
        uses: actions/download-artifact@v4
        with:
          name: macos-editor
          path: demo/addons/fmod/libs/macos/

      - name: Download macos template_debug libraries
        uses: actions/download-artifact@v4
        with:
          name: macos-template_debug
          path: demo/addons/fmod/libs/macos/

      - name: Download macos template_release libraries
        uses: actions/download-artifact@v4
        with:
          name: macos-template_release
          path: demo/addons/fmod/libs/macos/

      - name: Download iOS template_debug libraries
        uses: actions/download-artifact@v4
        with:
          name: ios-template_debug
          path: demo/addons/fmod/libs/iOS/

      - name: Download iOS template_release libraries
        uses: actions/download-artifact@v4
        with:
          name: ios-template_release
          path: demo/addons/fmod/libs/iOS/

      - name: Download android editor libraries
        uses: actions/download-artifact@v4
        with:
          name: android-editor
          path: demo/addons/fmod/libs/android/

      - name: Download android template_debug libraries
        uses: actions/download-artifact@v4
        with:
          name: android-template_debug
          path: demo/addons/fmod/libs/android/

      - name: Download android template_release libraries
        uses: actions/download-artifact@v4
        with:
          name: android-template_release
          path: demo/addons/fmod/libs/android/

      - name: Create Release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: Release ${{ github.ref }}
          draft: false
          prerelease: false

      - name: Zip fmod addon
        run: |
          cd demo/addons/
          zip -r addons.zip fmod -x '*/.gitignore'

      - name: Zip demo project (without .godot and GUT)
        run: |
          cd demo
          zip -r demo.zip . \
            -x '*/.gitignore' \
               '*.zip' \
               '.godot/*' '.godot/**' \
               'addons/gut/*' 'addons/gut/**' 'addons/gut' \
               '.gut*' \
               'run_tests.sh' \
               'test/' 'test/*' 'test/**' \

      - name: Upload Addon Asset
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
          asset_path: ./demo/addons/addons.zip
          asset_name: addons.zip
          asset_content_type: application/zip

      - name: Upload Demo Project Asset
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: ./demo/demo.zip
          asset_name: demo.zip
          asset_content_type: application/zip


================================================
FILE: .gitignore
================================================

# Created by https://www.gitignore.io/api/clion,cmake,scons
# Edit at https://www.gitignore.io/?templates=clion,cmake,scons
### OSX ###

.DS_Store

### Android ###

libs/
obj/

### CLion ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

CMakeLists.txt
bin/
*.os
*.o
*.obj

*.exp
*.lib

# Clion specific

.idea/*

# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

# Generated files
.idea/**/contentModel.xml

# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml

# Gradle
.idea/**/gradle.xml
.idea/**/libraries

# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn.  Uncomment if using
# auto-import.
# .idea/modules.xml
# .idea/*.iml
# .idea/modules

# CMake
cmake-build-*/

# Mongo Explorer plugin
.idea/**/mongoSettings.xml

# File-based project format
*.iws

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Cursive Clojure plugin
.idea/replstate.xml

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

# Editor-based Rest Client
.idea/httpRequests

# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

### CLion Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721

# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr

# Sonarlint plugin
.idea/sonarlint

### CMake ###
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps

### CMake Patch ###
# External projects
*-prefix/

### Visual Studio Generated Files ###
*.vcxproj
*.vcxproj.filters
*.sln

### SCons ###
# for projects that use SCons for building: http://http://www.scons.org/
.sconsign.dblite

# When configure fails, SCons outputs these
config.log
.sconf_temp

# End of https://www.gitignore.io/api/clion,cmake,scons

# uncomment when https://github.com/godotengine/godot/issues/71521 fix is in release.
#demo/.godot
**/*.editor

demo/addons/fmod/libs/android/aar/

*.pdb
.vs

================================================
FILE: .gitmodules
================================================
[submodule "godot-cpp"]
	path = godot-cpp
	url = https://github.com/godotengine/godot-cpp


================================================
FILE: .readthedocs.yml
================================================
# .readthedocs.yml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Set the OS, Python version and other tools you might need
build:
  os: ubuntu-22.04
  tools:
    python: "3.11"

# Build documentation with MkDocs
mkdocs:
 configuration: docs/mkdocs.yml

# Optionally set the version of Python and requirements required to build your docs
python:
  install:
    - requirements: docs/requirements.txt


================================================
FILE: Android.mk
================================================
# Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := fmod-core-prebuilt
LOCAL_SRC_FILES := ../libs/fmod/android/core/lib/$(TARGET_ARCH_ABI)/libfmod.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := fmod-studio-prebuilt
LOCAL_SRC_FILES := ../libs/fmod/android/studio/lib/$(TARGET_ARCH_ABI)/libfmodstudio.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := godot-prebuilt
ifeq ($(TARGET_ARCH_ABI),x86)
    LOCAL_SRC_FILES := ../godot-cpp/bin/libgodot-cpp.android.release.x86.a
endif
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
    LOCAL_SRC_FILES := ../godot-cpp/bin/libgodot-cpp.android.release.armv7.a
endif
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
    LOCAL_SRC_FILES := ../godot-cpp/bin/libgodot-cpp.android.release.arm64v8.a
endif
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libGodotFmod.android.release.$(TARGET_ARCH_ABI)
LOCAL_CPPFLAGS := -std=c++14
LOCAL_CPP_FEATURES := rtti exceptions
LOCAL_LDLIBS := -llog

LOCAL_SRC_FILES := \
src/godot_fmod.cpp \
src/gdlibrary.cpp \
src/callback/file_callbacks.cpp \
src/callback/event_callbacks.cpp \

LOCAL_SHARED_LIBRARIES := \
fmod-core-prebuilt \
fmod-studio-prebuilt

LOCAL_C_INCLUDES := \
../godot-cpp/godot-headers \
../godot-cpp/include/ \
../godot-cpp/include/core \
../godot-cpp/include/gen \
../libs/fmod/android/studio/inc \
../libs/fmod/android/core/inc

LOCAL_STATIC_LIBRARIES := godot-prebuilt

include $(BUILD_SHARED_LIBRARY)


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019 Utopia-Rise and Alex Fonseka

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
![logo](docs/src/doc/assets/fmod-gdextension-logo.png)

[![🌈 Build](https://github.com/utopia-rise/fmod-gdextension/actions/workflows/release.yml/badge.svg)](https://github.com/utopia-rise/fmod-gdextension/actions/workflows/release.yml) 
[![](https://img.shields.io/discord/1012326818365325352.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.com/invite/u2NM2vTGMn)
---

**Godot 4 GDExtension that integrates with the FMOD Studio API.** [FMOD is an audio engine and middleware solution](https://www.fmod.com/) for interactive audio in games. It has been the audio engine behind many
titles such as **Transistor**, **Into the Breach** and **Celeste**. This Godot extension is used by games such as [Koira](https://dont-nod.com/en/games/koira/).

If you need any help, you can join our [Discord Server](https://discord.com/invite/u2NM2vTGMn).

# Installation

1. [Download Latest Release](https://github.com/utopia-rise/fmod-gdextension/releases/latest)
2. Unpack the `addons/fmod` folder into your `/addons` folder within the Godot project
3. Enable this addon within the Godot settings: `Project > Project Settings > Plugins`

#### Read the [official docs](https://fmod-gdextension.readthedocs.io/en/latest/) to get started with this addon.

# Features

## 🔉 Seamless integration with FMOD

Use FMOD Studio to create bank files this addon will auto-load all events for you inside Godot Engine. Live updating works out of the box.

![fmod-events](docs/src/doc/assets/screenshot-01.png)

## 🔉 Dedicated Godot nodes

This GDExtension provides nodes such as `FmodEventEmitter2D`, `FmodEventEmitter3D`, `FmodEventListener2D` and `FmodEventListener3D` that can be used in any Godot scene or GDScript code.

![fmod-nodes](docs/src/doc/assets/screenshot-02.png)

# Contributing

In order to be able to PR this repo from a fork, you need to add `FMODUSER` and `FMODPASS` secrets to your fork repo.  
This enables CI to download FMOD api.

Feel free to raise pull requests. We hope you'll enjoy this addon!

## How this extension works

This GDExtension exposes most of the Studio API functions to Godot's GDScript and also provides helpers for performing
common functions like attaching Studio events to Godot nodes and playing 3D/positional audio.

> **Note:** This plugin doesn't provide C# bindings to FMOD. There is technically a C# FMOD API but we choose to develop it as a C++ GDExtension. Any language binding with a auto-binding feature for extensions should be able to use this plugin, which is the case for GDScript. C# doesn't offer this feature yet.

## Continuous Delivery

This project uses [Github Actions](https://github.com/features/actions) to continuously deploy released drivers. If you do not want to use those releases, you
can compile from sources by looking to [compile from sources section](./docs/src/doc/advanced/1-compiling.md). This project uses [SEMVER](https://semver.org/).

# Special Thanks

This project is a forked from [godot-fmod-integration](https://github.com/alexfonseka/godot-fmod-integration)
from [alexfonseka](https://github.com/alexfonseka). We'd like to thank him for the work he did, we simply adapted his
work to GDNative.

# Tested Versions

- **Godot Version:** 4.4 stable
- **FMOD Version:** 2.03

[fmodsingleton]: .README/fmodsingleton.png
[usecustombuild]: .README/usecustombuild.png


================================================
FILE: SConstruct
================================================
#!/usr/bin/env python
import os
import shutil
import subprocess

from SCons.Script import SConscript, ARGUMENTS, Action, Copy

target_path = ARGUMENTS.pop("target_path", "demo/addons/fmod/libs/")
target_name = ARGUMENTS.pop("target_name", "libGodotFmod")
fmod_lib_dir = ARGUMENTS.pop("fmod_lib_dir", "../libs/fmod/")

env = SConscript("godot-cpp/SConstruct")

# Add those directory manually, so we can skip the godot_cpp directory when including headers in C++ files
source_path = [
    os.path.join("godot-cpp", "include","godot_cpp"),
    os.path.join("godot-cpp", "gen", "include","godot_cpp")
]
env.Append(CPPPATH=[env.Dir(d) for d in source_path])

env.Replace(fmod_lib_dir = fmod_lib_dir)

# For the reference:
# - CCFLAGS are compilation flags shared between C and C++
# - CFLAGS are for C-specific compilation flags
# - CXXFLAGS are for C++-specific compilation flags
# - CPPFLAGS are for pre-processor flags
# - CPPDEFINES are for pre-processor defines
# - LINKFLAGS are for linking flags

# tweak this if you want to use different folders, or more folders, to store your source code in.
env.Append(CPPPATH=["src/"])
sources = [
    Glob('src/*.cpp'),
    Glob('src/callback/*.cpp'),
    Glob('src/core/*.cpp'),
    Glob('src/data/*.cpp'),
    Glob('src/tools/*.cpp'),
    Glob('src/helpers/*.cpp'),
    Glob('src/nodes/*.cpp'),
    Glob('src/resources/*.cpp'),
    Glob('src/studio/*.cpp'),
    Glob('src/plugins/*.cpp')
    ]

lfix = ""
debug = False
if env["target"] == "template_debug" or env["target"] == "editor":
    lfix = "L"
    debug = True

if env["platform"] == "macos":
    libfmod = 'libfmod%s.dylib' % lfix
    libfmodstudio = 'libfmodstudio%s.dylib' % lfix

    env.Append(CPPPATH=[env['fmod_lib_dir'] + 'osx/core/inc/', env['fmod_lib_dir'] + 'osx/studio/inc/'])
    env.Append(LIBPATH=[env['fmod_lib_dir'] + 'osx/core/lib/', env['fmod_lib_dir'] + 'osx/studio/lib/'])
    env.Append(LIBS=[libfmod, libfmodstudio])

    env.Append(
        LINKFLAGS=[
            "-framework",
            "Cocoa",
            "-Wl,-undefined,dynamic_lookup",
            "-rpath", "@loader_path/.."
        ]
    )

elif env["platform"] == "linux":
    libfmod = 'libfmod%s.so'% lfix
    libfmodstudio = 'libfmodstudio%s.so'% lfix

    env.Append(CPPPATH=[env['fmod_lib_dir'] + 'linux/core/inc/', env['fmod_lib_dir'] + 'linux/studio/inc/'])
    env.Append(LIBPATH=[env['fmod_lib_dir'] + 'linux/core/lib/' + env["arch"], env['fmod_lib_dir'] + 'linux/studio/lib/' + env["arch"]])
    env.Append(LIBS=[libfmod, libfmodstudio])

    env.Append(CCFLAGS=["-fPIC", "-Wwrite-strings"])
    env.Append(LINKFLAGS=["-Wl,-R,'$$ORIGIN'"])
    env.Append(LINKFLAGS=["-m64", "-fuse-ld=gold"])

elif env["platform"] == "windows":
    libfmod = 'fmod%s_vc'% lfix
    libfmodstudio = 'fmodstudio%s_vc'% lfix
    fmod_info_table = {
        "x86_64" : "x64",
        "x86_32" : "x86",
    }
    arch_suffix_override = fmod_info_table[env["arch"]]

    env.Append(CPPPATH=[env['fmod_lib_dir'] + 'windows/core/inc/', env['fmod_lib_dir'] + 'windows/studio/inc/'])
    env.Append(LIBPATH=[env['fmod_lib_dir'] + 'windows/core/lib/' + arch_suffix_override, env['fmod_lib_dir'] + 'windows/studio/lib/' + arch_suffix_override])
    env.Append(LIBS=[libfmod, libfmodstudio])

    env.Append(LINKFLAGS=["/WX"])
    if debug:
        env.Append(CCFLAGS=["/FS", "/Zi"])

elif env["platform"] == "ios":
    libfmod = 'libfmod%s_iphoneos.a' % lfix
    libfmodstudio = 'libfmodstudio%s_iphoneos.a' % lfix

    env.Append(CPPPATH=[env['fmod_lib_dir'] + 'ios/core/inc/', env['fmod_lib_dir'] + 'ios/studio/inc/'])
    env.Append(LIBPATH=[env['fmod_lib_dir'] + 'ios/core/lib/', env['fmod_lib_dir'] + 'ios/studio/lib/'])
    env.Append(LIBS=[libfmod, libfmodstudio])

    env.Append(LINKFLAGS=[
        '-Wl,-undefined,dynamic_lookup', "-miphoneos-version-min=" + env["ios_min_version"]
    ])

elif env["platform"] == "android":
    libfmod = 'libfmod%s.so' % lfix
    libfmodstudio = 'libfmodstudio%s.so' % lfix
    fmod_info_table = {
        "armv7": "armeabi-v7a",
        "arm64": "arm64-v8a",
        "x86": "x86",
        "x86_64": "x86_64"
    }
    arch_dir = fmod_info_table[env["arch"]]

    env.Append(CPPPATH=[env['fmod_lib_dir'] + 'android/core/inc/', env['fmod_lib_dir'] + 'android/studio/inc/'])
    env.Append(LIBPATH=[env['fmod_lib_dir'] + 'android/core/lib/' + arch_dir, env['fmod_lib_dir'] + 'android/studio/lib/' + arch_dir])
    env.Append(LIBS=[libfmod, libfmodstudio])

#Output is placed in the addons directory of the demo project directly
target = "{}{}/{}.{}.{}".format(
    target_path, env["platform"], target_name, env["platform"], env["target"]
) if env["platform"] != "android" else "{}{}/{}/{}.{}.{}".format(
    target_path, env["platform"], env["arch"], target_name, env["platform"], env["target"]
)

if env["platform"] == "macos":
    target = "{}.framework/{}.{}.{}".format(
        target,
        target_name,
        env["platform"],
        env["target"]
    )
else:
    target = "{}.{}{}".format(
        target,
        env["arch"],
        env["SHLIBSUFFIX"]
    )

library = env.SharedLibrary(target=target, source=sources)


def sys_exec(args):
    proc = subprocess.Popen(args, stdout=subprocess.PIPE, text=True)
    (out, err) = proc.communicate()
    return out.rstrip("\r\n").lstrip()


if env["platform"] == "ios":
    xcframework_path = "{}{}/{}.{}.{}.xcframework".format(
        target_path,
        env["platform"],
        target_name,
        env["platform"],
        env["target"]
    )

    def create_xcframework(self, arg, env, executor = None):
        sys_exec(["xcodebuild", "-create-xcframework", "-library", target, "-output", xcframework_path])
        sys_exec(["rm", target])
        sys_exec(["/usr/libexec/PlistBuddy", "-c", "Add :MinimumOSVersion string " + env["ios_min_version"], "{}/Info.plist".format(xcframework_path)])

    create_xcframework_action = Action('', create_xcframework)

    AddPostAction(library, create_xcframework_action)


def copy_fmod_libraries(self, arg, env, executor = None):
    fmod_core_lib_dir = ""
    fmod_studio_lib_dir = ""

    addon_fmod_libs_output = "{}{}/".format(
        target_path, env["platform"]
    ) if env["platform"] != "android" else "{}{}/{}/".format(
        target_path, env["platform"], env["arch"]
    )

    if env["platform"] == "macos":
        fmod_core_lib_dir = env['fmod_lib_dir'] + 'osx/core/lib/'
        fmod_studio_lib_dir = env['fmod_lib_dir'] + 'osx/studio/lib/'
    elif env["platform"] == "linux":
        fmod_core_lib_dir = env['fmod_lib_dir'] + 'linux/core/lib/' + env["arch"]
        fmod_studio_lib_dir = env['fmod_lib_dir'] + 'linux/studio/lib/' + env["arch"]
    elif env["platform"] == "windows":
        fmod_core_lib_dir = env['fmod_lib_dir'] + 'windows/core/lib/' + arch_suffix_override + '/'
        fmod_studio_lib_dir = env['fmod_lib_dir'] + 'windows/studio/lib/' + arch_suffix_override + '/'
    elif env["platform"] == "ios":
        fmod_core_lib_dir = env['fmod_lib_dir'] + 'ios/core/lib/'
        fmod_studio_lib_dir = env['fmod_lib_dir'] + 'ios/studio/lib/'
    elif env["platform"] == "android":
        fmod_core_lib_dir = env['fmod_lib_dir'] + 'android/core/lib/' + arch_dir
        fmod_studio_lib_dir = env['fmod_lib_dir'] + 'android/studio/lib/' + arch_dir

    source_files = [env.Glob(os.path.join(source_dir, '*.*')) for source_dir in [fmod_core_lib_dir, fmod_studio_lib_dir]]
    [[shutil.copy(str(file), addon_fmod_libs_output) for file in files] for files in source_files]


copy_fmod_libraries_action = Action('', copy_fmod_libraries)
AddPostAction(library, copy_fmod_libraries_action)

Default(library)

================================================
FILE: android-plugin/.gitignore
================================================
*.iml
.gradle
/local.properties
/.idea/
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
library/libraries/


================================================
FILE: android-plugin/build.gradle.kts
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
    id("com.android.library") version "8.0.0" apply false
    id("org.jetbrains.kotlin.android") version "2.1.20" apply false
}

================================================
FILE: android-plugin/gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists


================================================
FILE: android-plugin/gradle.properties
================================================
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

================================================
FILE: android-plugin/gradlew
================================================
#!/bin/sh

#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

##############################################################################
#
#   Gradle start up script for POSIX generated by Gradle.
#
#   Important for running:
#
#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
#       noncompliant, but you have some other compliant shell such as ksh or
#       bash, then to run this script, type that shell name before the whole
#       command line, like:
#
#           ksh Gradle
#
#       Busybox and similar reduced shells will NOT work, because this script
#       requires all of these POSIX shell features:
#         * functions;
#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
#         * compound commands having a testable exit status, especially «case»;
#         * various built-in commands including «command», «set», and «ulimit».
#
#   Important for patching:
#
#   (2) This script targets any POSIX shell, so it avoids extensions provided
#       by Bash, Ksh, etc; in particular arrays are avoided.
#
#       The "traditional" practice of packing multiple parameters into a
#       space-separated string is a well documented source of bugs and security
#       problems, so this is (mostly) avoided, by progressively accumulating
#       options in "$@", and eventually passing that to Java.
#
#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
#       see the in-line comments for details.
#
#       There are tweaks for specific operating systems such as AIX, CygWin,
#       Darwin, MinGW, and NonStop.
#
#   (3) This script is generated from the Groovy template
#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
#       within the Gradle project.
#
#       You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################

# Attempt to set APP_HOME

# Resolve links: $0 may be a link
app_path=$0

# Need this for daisy-chained symlinks.
while
    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
    [ -h "$app_path" ]
do
    ls=$( ls -ld "$app_path" )
    link=${ls#*' -> '}
    case $link in             #(
      /*)   app_path=$link ;; #(
      *)    app_path=$APP_HOME$link ;;
    esac
done

# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

warn () {
    echo "$*"
} >&2

die () {
    echo
    echo "$*"
    echo
    exit 1
} >&2

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in                #(
  CYGWIN* )         cygwin=true  ;; #(
  Darwin* )         darwin=true  ;; #(
  MSYS* | MINGW* )  msys=true    ;; #(
  NONSTOP* )        nonstop=true ;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar


# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD=$JAVA_HOME/jre/sh/java
    else
        JAVACMD=$JAVA_HOME/bin/java
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD=java
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
    case $MAX_FD in #(
      max*)
        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
        # shellcheck disable=SC3045
        MAX_FD=$( ulimit -H -n ) ||
            warn "Could not query maximum file descriptor limit"
    esac
    case $MAX_FD in  #(
      '' | soft) :;; #(
      *)
        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
        # shellcheck disable=SC3045
        ulimit -n "$MAX_FD" ||
            warn "Could not set maximum file descriptor limit to $MAX_FD"
    esac
fi

# Collect all arguments for the java command, stacking in reverse order:
#   * args from the command line
#   * the main class name
#   * -classpath
#   * -D...appname settings
#   * --module-path (only if needed)
#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.

# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )

    JAVACMD=$( cygpath --unix "$JAVACMD" )

    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    for arg do
        if
            case $arg in                                #(
              -*)   false ;;                            # don't mess with options #(
              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
                    [ -e "$t" ] ;;                      #(
              *)    false ;;
            esac
        then
            arg=$( cygpath --path --ignore --mixed "$arg" )
        fi
        # Roll the args list around exactly as many times as the number of
        # args, so each arg winds up back in the position where it started, but
        # possibly modified.
        #
        # NB: a `for` loop captures its iteration list before it begins, so
        # changing the positional parameters here affects neither the number of
        # iterations, nor the values presented in `arg`.
        shift                   # remove old arg
        set -- "$@" "$arg"      # push replacement arg
    done
fi

# Collect all arguments for the java command;
#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
#     shell script including quotes and variable substitutions, so put them in
#     double quotes to make sure that they get re-expanded; and
#   * put everything else in single quotes, so that it's not re-expanded.

set -- \
        "-Dorg.gradle.appname=$APP_BASE_NAME" \
        -classpath "$CLASSPATH" \
        org.gradle.wrapper.GradleWrapperMain \
        "$@"

# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
    die "xargs is not available"
fi

# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
#   set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#

eval "set -- $(
        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
        xargs -n1 |
        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
        tr '\n' ' '
    )" '"$@"'

exec "$JAVACMD" "$@"


================================================
FILE: android-plugin/gradlew.bat
================================================
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem      https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem

@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto execute

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar


@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*

:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: android-plugin/library/.gitignore
================================================
/build

================================================
FILE: android-plugin/library/build.gradle.kts
================================================

plugins {
    id("com.android.library")
    id("org.jetbrains.kotlin.android")
}

val pluginName = "fmod"
val pluginPackageName = "com.utopiarise.godot.fmod.android.plugin"

android {
    namespace = pluginPackageName
    compileSdk = 33

    defaultConfig {
        minSdk = 24
        targetSdk = 33

        manifestPlaceholders["godotPluginName"] = pluginName
        manifestPlaceholders["godotPluginPackageName"] = pluginPackageName
        buildConfigField("String", "GODOT_PLUGIN_NAME", "\"${pluginName}\"")
        setProperty("archivesBaseName", pluginName)
    }

    buildFeatures {
        buildConfig = true
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            buildConfigField("boolean", "DEBUG", "false")
        }

        debug {
            buildConfigField("boolean", "DEBUG", "true")
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
    kotlinOptions {
        jvmTarget = "17"
    }
}

val copyDebugAARToDemoAddons by tasks.registering(Copy::class) {
    description = "Copies the generated debug AAR binary to the plugin's addons directory"
    from("build/outputs/aar")
    include("$pluginName-debug.aar")
    into("../../demo/addons/$pluginName/libs/android")
}

val copyReleaseAARToDemoAddons by tasks.registering(Copy::class) {
    description = "Copies the generated release AAR binary to the plugin's addons directory"
    from("build/outputs/aar")
    include("$pluginName-release.aar")
    into("../../demo/addons/$pluginName/libs/android")
}


tasks.named("assemble").configure {
    finalizedBy(copyDebugAARToDemoAddons)
    finalizedBy(copyReleaseAARToDemoAddons)
}

dependencies {
    implementation(files("libraries/fmod.jar"))
    implementation("org.godotengine:godot:4.5.0.stable")
}

================================================
FILE: android-plugin/library/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
>

    <application>
        <meta-data
                android:name="org.godotengine.plugin.v2.FmodPlugin"
                android:value="com.utopiarise.godot.fmod.android.plugin.FmodPlugin" />
    </application>

</manifest>

================================================
FILE: android-plugin/library/src/main/kotlin/com/utopiarise/godot/fmod/android/plugin/FmodPlugin.kt
================================================
package com.utopiarise.godot.fmod.android.plugin

import android.app.Activity
import android.view.View
import org.fmod.FMOD
import org.godotengine.godot.Godot
import org.godotengine.godot.plugin.GodotPlugin

class FmodPlugin(godot: Godot) : GodotPlugin(godot) {
    override fun getPluginName() = "Godot Fmod Android Plugin"

    override fun onMainCreate(activity: Activity?): View? {
        FMOD.init(activity)
        return super.onMainCreate(activity)
    }

    override fun onMainDestroy() {
        FMOD.close()
    }

    companion object {
        init {
            if (BuildConfig.DEBUG) {
                System.loadLibrary("fmodL")
                System.loadLibrary("fmodstudioL")
            } else {
                System.loadLibrary("fmod")
                System.loadLibrary("fmodstudio")
            }
        }
    }
}

================================================
FILE: android-plugin/library/src/main/resources/fmod-android-license.txt
================================================
Copyright (C) 2010 The Android Open Source Project All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following
disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

================================================
FILE: android-plugin/settings.gradle.kts
================================================
pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.name = "Godot Fmod Android Plugin"
include(":library")
 

================================================
FILE: demo/.gitattributes
================================================
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf


================================================
FILE: demo/.gitignore
================================================

# Godot 4+ specific ignores
.godot/

# Godot-specific ignores
.import/
export.cfg
export_credentials.cfg

# Imported translations (automatically generated from CSV files)
*.translation

# Mono-specific ignores
.mono/
data_*/
mono_crash.*.json

.vscode/
logs/
**/*.aar
android/build
android/

================================================
FILE: demo/.gutconfig.json
================================================
{
 "background_color": "262626ff",
 "compact_mode": false,
 "configured_dirs": [
  "res://test/unit"
 ],
 "dirs": [
  "res://test/unit"
 ],
 "disable_colors": false,
 "double_strategy": 1,
 "failure_error_types": [
  "gut"
 ],
 "font_color": "ccccccff",
 "font_name": "CourierPrime",
 "font_size": 16.0,
 "gut_on_top": true,
 "hide_orphans": false,
 "ignore_pause": false,
 "include_subdirs": false,
 "junit_xml_file": "",
 "junit_xml_timestamp": false,
 "log_level": 1.0,
 "no_error_tracking": false,
 "opacity": 100.0,
 "paint_after": 0.1,
 "post_run_script": "",
 "pre_run_script": "",
 "prefix": "test_",
 "should_exit": true,
 "should_exit_on_success": false,
 "should_maximize": false,
 "suffix": ".gd",
 "wait_log_delay": 0.5
}


================================================
FILE: demo/addons/fmod/.gitignore
================================================
*.dll
*.a
*.dylib
*.so
*.so.*
*.xcframework
!libs/

================================================
FILE: demo/addons/fmod/FmodAndroidExportPlugin.gd
================================================
@tool
class_name FmodAndroidExportPlugin extends EditorExportPlugin

var plugin_name: String = "fmod"

func _supports_platform(platform):
	if platform is EditorExportPlatformAndroid:
		return true
	return false

func _get_android_libraries(platform, debug):
	if debug:
		return PackedStringArray([plugin_name + "/libs/android/" + plugin_name + "-debug.aar"])
	else:
		return PackedStringArray([plugin_name + "/libs/android/" + plugin_name + "-release.aar"])


func _get_name():
	return plugin_name


================================================
FILE: demo/addons/fmod/FmodAndroidExportPlugin.gd.uid
================================================
uid://cle6f2srp4yun


================================================
FILE: demo/addons/fmod/FmodManager.gd
================================================
@tool
extends Node

var performance_display: PerformancesDisplay

func _ready():
	process_mode = PROCESS_MODE_ALWAYS
	performance_display = PerformancesDisplay.new()
	add_child(performance_display)

func _exit_tree() -> void:
	remove_child(performance_display)
	performance_display.free()

func _process(delta):
	FmodServer.update()
	
func _notification(what):
	FmodServer.notification(what)

	if OS.has_feature("mobile"):
		match what:
			NOTIFICATION_APPLICATION_FOCUS_OUT: FmodServer.mixer_suspend()
			NOTIFICATION_APPLICATION_FOCUS_IN: FmodServer.mixer_resume()


================================================
FILE: demo/addons/fmod/FmodManager.gd.uid
================================================
uid://cds10pm7hwn3p


================================================
FILE: demo/addons/fmod/FmodPlugin.gd
================================================
@tool
class_name FmodPlugin extends EditorPlugin


const ADDON_PATH: StringName = &"res://addons/fmod"
const FmodManager_Autoload_Name: StringName = &"FmodManager"
@onready var theme: Theme = get_editor_interface().get_base_control().get_theme()

var fmod_bank_explorer_window: PackedScene = load("res://addons/fmod/tool/ui/FmodBankExplorer.tscn")
var bank_explorer: FmodBankExplorer
var fmod_button: Button
var export_plugin: FmodEditorExportPlugin = FmodEditorExportPlugin.new()
var android_export_plugin: FmodAndroidExportPlugin = FmodAndroidExportPlugin.new()
var emitter_inspector_plugin: FmodEmitterPropertyInspectorPlugin = FmodEmitterPropertyInspectorPlugin.new(self)
var bank_loader_inspector_plugin: FmodBankLoaderPropertyInspectorPlugin = FmodBankLoaderPropertyInspectorPlugin.new(self)

func _init() -> void:
	FmodBankDatabase.reload_all_banks()

func _enable_plugin() -> void:
	add_autoload_singleton(FmodManager_Autoload_Name, "res://addons/fmod/FmodManager.gd")

func _disable_plugin() -> void:
	remove_autoload_singleton(FmodManager_Autoload_Name)

func _enter_tree() -> void:
	_add_explorer_button()
	
	_add_bank_explorer_window()

	add_inspector_plugin(bank_loader_inspector_plugin)
	add_inspector_plugin(emitter_inspector_plugin)
	
	add_export_plugin(export_plugin)
	add_export_plugin(android_export_plugin)

func _exit_tree() -> void:
	remove_control_from_container(EditorPlugin.CONTAINER_TOOLBAR, fmod_button)
	fmod_button.queue_free()
	
	bank_explorer.queue_free()
	
	remove_inspector_plugin(emitter_inspector_plugin)
	remove_inspector_plugin(bank_loader_inspector_plugin)

	remove_export_plugin(android_export_plugin)
	remove_export_plugin(export_plugin)

func _add_explorer_button() -> void:
	fmod_button = Button.new()
	fmod_button.icon = load("res://addons/fmod/icons/fmod_icon.svg")
	fmod_button.text = "Fmod Explorer"
	
	fmod_button.pressed.connect(_on_project_explorer_button_clicked)
	
	add_control_to_container(EditorPlugin.CONTAINER_TOOLBAR, fmod_button)

func _add_bank_explorer_window() -> void:
	bank_explorer = fmod_bank_explorer_window.instantiate()
	bank_explorer.theme = get_editor_interface().get_base_control().get_theme()
	bank_explorer.visible = false
	
	add_child(bank_explorer)

func _on_project_explorer_button_clicked() -> void:
	bank_explorer.should_display_copy_buttons = true
	bank_explorer.should_display_select_button = false
	_popup_project_explorer(FmodBankExplorer.ToDisplayFlags.BUSES | FmodBankExplorer.ToDisplayFlags.VCA | FmodBankExplorer.ToDisplayFlags.EVENTS)

func open_project_explorer_events(on_select_callable: Callable) -> void:
	_open_project_explorer(FmodBankExplorer.ToDisplayFlags.EVENTS, on_select_callable)

func open_project_explorer_bank(on_select_callable: Callable) -> void:
	_open_project_explorer(0, on_select_callable)

func _open_project_explorer(display_flag: int, on_select_callable: Callable) -> void:
	bank_explorer.should_display_copy_buttons = false
	bank_explorer.should_display_select_button = true
	_popup_project_explorer(display_flag, on_select_callable)

func _popup_project_explorer(to_display: int, callable: Callable = Callable()) -> void:
	if bank_explorer.visible == true:
		bank_explorer.close_window()
		return
	
	bank_explorer.flags = to_display
	bank_explorer.reset_search()
	bank_explorer.regenerate_tree(callable)
	bank_explorer.popup_centered()
	


================================================
FILE: demo/addons/fmod/FmodPlugin.gd.uid
================================================
uid://cwsif6rhp50p5


================================================
FILE: demo/addons/fmod/fmod.gdextension
================================================
[configuration]
entry_symbol = "fmod_library_init"
compatibility_minimum = 4.5

[libraries]
windows.editor.x86_64 = "res://addons/fmod/libs/windows/libGodotFmod.windows.editor.x86_64.dll"
windows.debug.x86_64 = "res://addons/fmod/libs/windows/libGodotFmod.windows.template_debug.x86_64.dll"
windows.release.x86_64 = "res://addons/fmod/libs/windows/libGodotFmod.windows.template_release.x86_64.dll"
macos.editor = "res://addons/fmod/libs/macos/libGodotFmod.macos.editor.framework"
macos.debug  = "res://addons/fmod/libs/macos/libGodotFmod.macos.template_debug.framework"
macos.release  = "res://addons/fmod/libs/macos/libGodotFmod.macos.template_release.framework"
linux.editor.x86_64 = "res://addons/fmod/libs/linux/libGodotFmod.linux.editor.x86_64.so"
linux.debug.x86_64 = "res://addons/fmod/libs/linux/libGodotFmod.linux.template_debug.x86_64.so"
linux.release.x86_64 = "res://addons/fmod/libs/linux/libGodotFmod.linux.template_release.x86_64.so"
android.debug.x86_64 = "res://addons/fmod/libs/android/x86_64/libGodotFmod.android.template_debug.x86_64.so"
android.release.x86_64 = "res://addons/fmod/libs/android/x86_64/libGodotFmod.android.template_release.x86_64.so"
android.debug.arm64 = "res://addons/fmod/libs/android/arm64/libGodotFmod.android.template_debug.arm64.so"
android.release.arm64 = "res://addons/fmod/libs/android/arm64/libGodotFmod.android.template_release.arm64.so"
ios.debug  = "res://addons/fmod/libs/ios/libGodotFmod.ios.template_debug.xcframework"
ios.release  = "res://addons/fmod/libs/ios/libGodotFmod.ios.template_release.xcframework"

[icons]
FmodEventEmitter2D = "res://addons/fmod/icons/fmod_icon.svg"
FmodEventEmitter3D = "res://addons/fmod/icons/fmod_icon.svg"
FmodListener2D = "res://addons/fmod/icons/fmod_icon.svg"
FmodListener3D = "res://addons/fmod/icons/fmod_icon.svg"
FmodBankLoader = "res://addons/fmod/icons/fmod_icon.svg"

[dependencies]
windows.editor.x86_64 = {
"libs/windows/fmodL.dll": "",
"libs/windows/fmodstudioL.dll": ""
}
windows.debug.x86_64 = {
"libs/windows/fmodL.dll": "", 
"libs/windows/fmodstudioL.dll": ""
}
windows.release.x86_64 = {
"libs/windows/fmod.dll": "", 
"libs/windows/fmodstudio.dll": ""
}
linux.editor.x86_64  = {
"libs/linux/libfmodL.so": "",
"libs/linux/libfmodL.so.14": "",
"libs/linux/libfmodL.so.14.6": "",
"libs/linux/libfmodstudioL.so": "",
"libs/linux/libfmodstudioL.so.14": "",
"libs/linux/libfmodstudioL.so.14.6": ""
}
linux.debug.x86_64  = {
"libs/linux/libfmodL.so": "",
"libs/linux/libfmodL.so.14": "",
"libs/linux/libfmodL.so.14.6": "",
"libs/linux/libfmodstudioL.so": "",
"libs/linux/libfmodstudioL.so.14": "",
"libs/linux/libfmodstudioL.so.14.6": ""
}
linux.release.x86_64 = {
"libs/linux/libfmod.so": "",
"libs/linux/libfmod.so.14": "",
"libs/linux/libfmod.so.14.6": "",
"libs/linux/libfmodstudio.so": "",
"libs/linux/libfmodstudio.so.14": "",
"libs/linux/libfmodstudio.so.14.6": ""
}
macos.editor  = {
"libs/macos/libfmodL.dylib": "",
"libs/macos/libfmodstudioL.dylib": ""
}
macos.debug  = {
"libs/macos/libfmodL.dylib": "",
"libs/macos/libfmodstudioL.dylib": ""
}
macos.release = {
"libs/macos/libfmod.dylib": "",
"libs/macos/libfmodstudio.dylib": ""
}
android.debug.x86_64 = {
"libs/android/x86_64/libfmodL.so": "",
"libs/android/x86_64/libfmodstudioL.so": "",
}
android.release.x86_64 = {
"libs/android/x86_64/libfmod.so": "",
"libs/android/x86_64/libfmodstudio.so": "",
}
android.debug.arm64 = {
"libs/android/arm64/libfmodL.so": "",
"libs/android/arm64/libfmodstudioL.so": "",
}
android.release.arm64 = {
"libs/android/arm64/libfmod.so": "",
"libs/android/arm64/libfmodstudio.so": "",
}
ios.debug  = {
"libs/ios/libfmodL_iphoneos.a": "",
"libs/ios/libfmodstudioL_iphoneos.a": ""
}
ios.release = {
"libs/ios/libfmod_iphoneos.a": "",
"libs/ios/libfmodstudio_iphoneos.a": ""
}

================================================
FILE: demo/addons/fmod/fmod.gdextension.uid
================================================
uid://dq17s7r52klxe


================================================
FILE: demo/addons/fmod/icons/bank_icon.svg.import
================================================
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://o2chsr07oeqs"
path="res://.godot/imported/bank_icon.svg-8de6c7bff09a67352e162b3c61b601de.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}

[deps]

source_file="res://addons/fmod/icons/bank_icon.svg"
dest_files=["res://.godot/imported/bank_icon.svg-8de6c7bff09a67352e162b3c61b601de.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=true


================================================
FILE: demo/addons/fmod/icons/bus_icon.svg.import
================================================
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://dj1kag4aeg58t"
path="res://.godot/imported/bus_icon.svg-f536ffd3c4893e79a9d3cb9a1b4fb50c.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}

[deps]

source_file="res://addons/fmod/icons/bus_icon.svg"
dest_files=["res://.godot/imported/bus_icon.svg-f536ffd3c4893e79a9d3cb9a1b4fb50c.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=true


================================================
FILE: demo/addons/fmod/icons/c_parameter_icon.svg.import
================================================
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://cmvcqfsl167te"
path="res://.godot/imported/c_parameter_icon.svg-04115c2482c9a6874356ffdc09c41db0.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}

[deps]

source_file="res://addons/fmod/icons/c_parameter_icon.svg"
dest_files=["res://.godot/imported/c_parameter_icon.svg-04115c2482c9a6874356ffdc09c41db0.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=true


================================================
FILE: demo/addons/fmod/icons/d_parameter_icon.svg.import
================================================
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://dgna04txtwnyb"
path="res://.godot/imported/d_parameter_icon.svg-d339e4e3f950ae8593b999ef51579136.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}

[deps]

source_file="res://addons/fmod/icons/d_parameter_icon.svg"
dest_files=["res://.godot/imported/d_parameter_icon.svg-d339e4e3f950ae8593b999ef51579136.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=true


================================================
FILE: demo/addons/fmod/icons/event_icon.svg.import
================================================
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://cmpgmbn3y4svl"
path="res://.godot/imported/event_icon.svg-4e6e2103d076f95b7bef82f079e433e6.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}

[deps]

source_file="res://addons/fmod/icons/event_icon.svg"
dest_files=["res://.godot/imported/event_icon.svg-4e6e2103d076f95b7bef82f079e433e6.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=true


================================================
FILE: demo/addons/fmod/icons/fmod_emitter.png.import
================================================
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://cotpb54utx6d6"
path="res://.godot/imported/fmod_emitter.png-6783a287e298e2a04e64a6deaa6fe366.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://addons/fmod/icons/fmod_emitter.png"
dest_files=["res://.godot/imported/fmod_emitter.png-6783a287e298e2a04e64a6deaa6fe366.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1


================================================
FILE: demo/addons/fmod/icons/fmod_icon.svg.import
================================================
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://bwqq5q7kodk40"
path="res://.godot/imported/fmod_icon.svg-cca7eb13231881fafaea0d598d407ea3.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}

[deps]

source_file="res://addons/fmod/icons/fmod_icon.svg"
dest_files=["res://.godot/imported/fmod_icon.svg-cca7eb13231881fafaea0d598d407ea3.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=true


================================================
FILE: demo/addons/fmod/icons/snapshot_icon.svg.import
================================================
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://b4jxbh86chubi"
path="res://.godot/imported/snapshot_icon.svg-7b517248819b3685844766808fbce2a5.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}

[deps]

source_file="res://addons/fmod/icons/snapshot_icon.svg"
dest_files=["res://.godot/imported/snapshot_icon.svg-7b517248819b3685844766808fbce2a5.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=true


================================================
FILE: demo/addons/fmod/icons/vca_icon.svg.import
================================================
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://crsj4jjaeq87a"
path="res://.godot/imported/vca_icon.svg-def43f27fe148a7a0b18c7dcaab20c79.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
}

[deps]

source_file="res://addons/fmod/icons/vca_icon.svg"
dest_files=["res://.godot/imported/vca_icon.svg-def43f27fe148a7a0b18c7dcaab20c79.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=true
editor/convert_colors_with_editor_theme=true


================================================
FILE: demo/addons/fmod/libs/android/arm64/CopyPast_Fmod_Libs_Here.txt
================================================


================================================
FILE: demo/addons/fmod/libs/iOS/CopyPast_Fmod_Libs_Here.txt
================================================


================================================
FILE: demo/addons/fmod/libs/linux/CopyPast_Fmod_Libs_Here.txt
================================================


================================================
FILE: demo/addons/fmod/libs/macos/CopyPast_Fmod_Libs_Here.txt
================================================


================================================
FILE: demo/addons/fmod/libs/macos/libGodotFmod.macos.editor.framework/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleExecutable</key>
	<string>libGodotFmod.macos.editor</string>
	<key>CFBundleIdentifier</key>
	<string>com.utopia-rise.fmod-gdextension</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>libGodotFmod.macos.editor</string>
	<key>CFBundlePackageType</key>
	<string>FMWK</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0.0</string>
	<key>CFBundleSupportedPlatforms</key>
	<array>
		<string>MacOSX</string>
	</array>
	<key>CFBundleVersion</key>
	<string>1.0.0</string>
	<key>LSMinimumSystemVersion</key>
	<string>10.12</string>
</dict>
</plist>

================================================
FILE: demo/addons/fmod/libs/macos/libGodotFmod.macos.template_debug.framework/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleExecutable</key>
	<string>libGodotFmod.macos.template_debug</string>
	<key>CFBundleIdentifier</key>
	<string>com.utopiarise.fmod-gdextension</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>libGodotFmod.macos.template_debug</string>
	<key>CFBundlePackageType</key>
	<string>FMWK</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0.0</string>
	<key>CFBundleSupportedPlatforms</key>
	<array>
		<string>MacOSX</string>
	</array>
	<key>CFBundleVersion</key>
	<string>1.0.0</string>
	<key>LSMinimumSystemVersion</key>
	<string>10.12</string>
</dict>
</plist>

================================================
FILE: demo/addons/fmod/libs/macos/libGodotFmod.macos.template_release.framework/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleExecutable</key>
	<string>libGodotFmod.macos.template_release</string>
	<key>CFBundleIdentifier</key>
	<string>com.utopiarise.fmod-gdextension</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>libGodotFmod.macos.template_release</string>
	<key>CFBundlePackageType</key>
	<string>FMWK</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0.0</string>
	<key>CFBundleSupportedPlatforms</key>
	<array>
		<string>MacOSX</string>
	</array>
	<key>CFBundleVersion</key>
	<string>1.0.0</string>
	<key>LSMinimumSystemVersion</key>
	<string>10.12</string>
</dict>
</plist>

================================================
FILE: demo/addons/fmod/libs/windows/CopyPast_Fmod_Libs_Here.txt
================================================


================================================
FILE: demo/addons/fmod/plugin.cfg
================================================
[plugin]

name="FMOD GDExtension"
description="FMOD GDExtension for Godot Engine 4.5"
author="Utopia-rise, Tristan Grespinet, Pierre-Thomas Meisels"
version="6.1.0"
script="FmodPlugin.gd"


================================================
FILE: demo/addons/fmod/tool/FmodBankDatabase.gd
================================================
extends Node

class_name FmodBankDatabase


static var banks := Array()
const MASTER_STRINGS_BANK_NAME = "Master.strings.bank"
const MASTER_BANK_NAME = "Master.bank"

static func reload_all_banks(): 
	banks.clear()
	
	var banks_root = ProjectSettings.get_setting("Fmod/General/banks_path", "")
	var master_strings_bank_path = "%s/%s" % [banks_root, MASTER_STRINGS_BANK_NAME]
	var master_bank_path = "%s/%s" % [banks_root, MASTER_BANK_NAME]
	
	if not FileAccess.file_exists(master_strings_bank_path):
		push_warning("Cannot find master strings bank at %s" % master_strings_bank_path)
		return
	
	if not FileAccess.file_exists(master_bank_path):
		push_warning("Cannot find master bank at %s" % master_bank_path)
		return
	
	banks.append(
		FmodServer.load_bank(master_strings_bank_path, FmodServer.FMOD_STUDIO_LOAD_BANK_NORMAL)
	)
	banks.append(
		FmodServer.load_bank(master_bank_path, FmodServer.FMOD_STUDIO_LOAD_BANK_NORMAL)
	)

	var dir: DirAccess = DirAccess.open(banks_root)
	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
			elif file_name.ends_with(".bank") and file_name != MASTER_STRINGS_BANK_NAME and file_name != MASTER_BANK_NAME:
				banks.append(
					FmodServer.load_bank("%s/%s" % [banks_root, file_name], FmodServer.FMOD_STUDIO_LOAD_BANK_NORMAL)
				)
			file_name = dir.get_next()
	


================================================
FILE: demo/addons/fmod/tool/FmodBankDatabase.gd.uid
================================================
uid://dovuikgbkylhi


================================================
FILE: demo/addons/fmod/tool/inspectors/FmodBankLoaderPropertyInspectorPlugin.gd
================================================
class_name FmodBankLoaderPropertyInspectorPlugin extends EditorInspectorPlugin

static var bank_icon = load("res://addons/fmod/icons/bank_icon.svg")

var _open_project_explorer_callable: Callable

func _init(plugin: FmodPlugin):
	_open_project_explorer_callable = plugin.open_project_explorer_bank

func _can_handle(object: Object):
	return object is FmodBankLoader

func _parse_property(object: Object, type: Variant.Type, name: String, hint_type: PropertyHint, hint_string: String, usage_flags: int, wide: bool):
	return name == "bank_paths"

func _parse_category(object: Object, category: String):
	if category != "FmodBankLoader":
		return
	var editor_property := FmodBankPathEditorProperty.new(_open_project_explorer_callable)
	add_property_editor("bank_paths", editor_property, false, "Fmod banks")


================================================
FILE: demo/addons/fmod/tool/inspectors/FmodBankLoaderPropertyInspectorPlugin.gd.uid
================================================
uid://tnljjxahubam


================================================
FILE: demo/addons/fmod/tool/inspectors/FmodEmitterPropertyInspectorPlugin.gd
================================================
class_name FmodEmitterPropertyInspectorPlugin extends EditorInspectorPlugin

var _open_project_explorer_callable: Callable
var _event_editor_property_scene: PackedScene = load("res://addons/fmod/tool/property_editors/FmodEventEditorProperty.tscn")

func _init(plugin: FmodPlugin):
	_open_project_explorer_callable = plugin.open_project_explorer_events

func _can_handle(object: Object):
	return object is FmodEventEmitter2D or \
	object is FmodEventEmitter3D

func _parse_property(object: Object, type: Variant.Type, name: String, hint_type: PropertyHint, hint_string: String, usage_flags: int, wide: bool):
	return name == "event_name" || name == "event_guid"

func _parse_category(object: Object, category: String):
	if category != "FmodEventEmitter2D" and category != "FmodEventEmitter3D":
		return
	var editor_property := _event_editor_property_scene.instantiate()
	editor_property.initialize(_open_project_explorer_callable, "event_name", "event_guid")
	add_property_editor_for_multiple_properties("Fmod event", PackedStringArray(["event_name", "event_guid"]), editor_property)


================================================
FILE: demo/addons/fmod/tool/inspectors/FmodEmitterPropertyInspectorPlugin.gd.uid
================================================
uid://co1ktq45h26wx


================================================
FILE: demo/addons/fmod/tool/performances/PerformancesDisplay.gd
================================================
class_name PerformancesDisplay extends Node


const CORE_CPU_DSP_CATEGORY = "FMOD [Core]/Cpu DSP"
const CORE_CPU_GEOMETRY_CATEGORY = "FMOD [Core]/Cpu Geometry"
const CORE_CPU_STREAM_CATEGORY = "FMOD [Core]/Cpu Stream"
const CORE_CPU_UPDATE_CATEGORY = "FMOD/[Core] Cpu Update"
const CORE_CPU_CONVOLUTION_THREAD1_CATEGORY = "FMOD/[Core] Cpu convolution Thread 1"
const CORE_CPU_CONVOLUTION_THREAD2_CATEGORY = "FMOD/[Core] Cpu convolution Thread 2"

const STUDIO_CPU_UPDATE_CATEGORY = "FMOD/[Studio] Cpu Update"

const MEMORY_CURRENTLY_ALLOCATED_CATEGORY = "FMOD/[Memory] Currently allocated"
const MEMORY_MAX_ALLOCATED_CATEGORY = "FMOD/[Memory] Max allocated"

const FILE_SAMPLE_CATEGORY = "FMOD/[File] Sample bytes read"
const FILE_STREAM_CATEGORY = "FMOD/[File] Stream bytes read"
const FILE_OTHER_CATEGORY = "FMOD/[File] Other bytes read"

func _enter_tree():
	var performance_data: FmodPerformanceData = FmodServer.get_performance_data()
	add_monitor(CORE_CPU_DSP_CATEGORY, func(): return performance_data.dsp)
	add_monitor(CORE_CPU_GEOMETRY_CATEGORY, func(): return performance_data.geometry)
	add_monitor(CORE_CPU_STREAM_CATEGORY, func(): return performance_data.stream)
	add_monitor(CORE_CPU_UPDATE_CATEGORY, func(): return performance_data.update)
	add_monitor(CORE_CPU_CONVOLUTION_THREAD1_CATEGORY, func(): return performance_data.convolution1)
	add_monitor(CORE_CPU_CONVOLUTION_THREAD2_CATEGORY, func(): return performance_data.convolution2)
	
	add_monitor(STUDIO_CPU_UPDATE_CATEGORY, func(): return performance_data.studio)
	
	add_monitor(MEMORY_CURRENTLY_ALLOCATED_CATEGORY, func(): return performance_data.currently_allocated)
	add_monitor(MEMORY_MAX_ALLOCATED_CATEGORY, func(): return performance_data.max_allocated)
	
	add_monitor(FILE_SAMPLE_CATEGORY, func(): return performance_data.sample_bytes_read)
	add_monitor(FILE_STREAM_CATEGORY, func(): return performance_data.stream_bytes_read)
	add_monitor(FILE_OTHER_CATEGORY, func(): return performance_data.other_bytes_read)

func _exit_tree() -> void:
	remove_monitor(CORE_CPU_DSP_CATEGORY)
	remove_monitor(CORE_CPU_GEOMETRY_CATEGORY)
	remove_monitor(CORE_CPU_STREAM_CATEGORY)
	remove_monitor(CORE_CPU_UPDATE_CATEGORY)
	remove_monitor(CORE_CPU_CONVOLUTION_THREAD1_CATEGORY)
	remove_monitor(CORE_CPU_CONVOLUTION_THREAD2_CATEGORY)
	
	remove_monitor(STUDIO_CPU_UPDATE_CATEGORY)
	
	remove_monitor(MEMORY_CURRENTLY_ALLOCATED_CATEGORY)
	remove_monitor(MEMORY_MAX_ALLOCATED_CATEGORY)
	
	remove_monitor(FILE_SAMPLE_CATEGORY)
	remove_monitor(FILE_STREAM_CATEGORY)
	remove_monitor(FILE_OTHER_CATEGORY)

func add_monitor(title: String, callable: Callable) -> void:
	if not Performance.has_custom_monitor(title):
		Performance.add_custom_monitor(title, callable)

func remove_monitor(title: String) -> void:
	if Performance.has_custom_monitor(title):
		Performance.remove_custom_monitor(title)


================================================
FILE: demo/addons/fmod/tool/performances/PerformancesDisplay.gd.uid
================================================
uid://bc0uajlvc0u00


================================================
FILE: demo/addons/fmod/tool/property_editors/FmodBankPathEditorProperty.gd
================================================
class_name FmodBankPathEditorProperty extends EditorProperty

var path_property_name := "bank_paths"

var ui: Control
var last_selected_index := -1

func _init(open_project_explorer_callable: Callable):
	ui = load("res://addons/fmod/tool/property_editors/FmodBankPathsPropertyEditorUi.tscn").instantiate()
	add_child(ui)
	var add_button: Button = ui.get_node("%AddButton")
	
	var open_project_explorer_event = func open_project_explorer_event():
		open_project_explorer_callable.call(self._set_path_and_guid)
	add_button.pressed.connect(open_project_explorer_event)
	
	var remove_button: Button = ui.get_node("%RemoveButton")
	remove_button.pressed.connect(_on_remove_button)
	
	var manual_add_button: Button = ui.get_node("%ManualAddButton")
	manual_add_button.pressed.connect(_on_manual_add_button)
	
	var up_button: Button = ui.get_node("%UpButton")
	up_button.pressed.connect(_on_move_button.bind(false))
	
	var down_button: Button = ui.get_node("%DownButton")
	down_button.pressed.connect(_on_move_button.bind(true))

func _update_property():
	var bank_list: ItemList = ui.get_node("%BankList")
	bank_list.clear()
	var bank_paths: Array = get_edited_object()[path_property_name]
	for path in bank_paths:
		bank_list.add_item(path)
	
	if last_selected_index == -1:
		return
	bank_list.select(last_selected_index)
	last_selected_index = -1

func _set_path_and_guid(path: String, _cancel: String):
	var current_bank_paths: Array = get_edited_object()[path_property_name]
	
	if current_bank_paths.has(path):
		return
	
	var bank_paths := Array(current_bank_paths)
	bank_paths.append(path)
	emit_changed(path_property_name, bank_paths)

func _on_remove_button():
	var bank_list: ItemList = ui.get_node("%BankList")
	var current_bank_paths: Array = get_edited_object()[path_property_name]
	var bank_paths := Array(current_bank_paths)
	var selected_items_indexes: PackedInt32Array = bank_list.get_selected_items()
	if selected_items_indexes.is_empty():
		return
	var item = bank_list.get_item_text(selected_items_indexes[0])
	var in_list_index = bank_paths.find(item)
	bank_paths.remove_at(in_list_index)
	last_selected_index = in_list_index if in_list_index < bank_paths.size() else in_list_index - 1
	emit_changed(path_property_name, bank_paths)

func _on_manual_add_button():
	var manual_add_line_edit: LineEdit = ui.get_node("%ManualAddLineEdit")
	var to_add: String = manual_add_line_edit.text
	if not to_add.begins_with("res://") || not to_add.ends_with(".bank"):
		return
	_set_path_and_guid(to_add, "")
	manual_add_line_edit.text = ""

func _on_move_button(is_down: bool):
	var bank_list: ItemList = ui.get_node("%BankList")
	var current_bank_paths: Array = get_edited_object()[path_property_name]
	var bank_paths := Array(current_bank_paths)
	var selected_items_indexes: PackedInt32Array = bank_list.get_selected_items()
	if selected_items_indexes.is_empty():
		return
	var item = bank_list.get_item_text(selected_items_indexes[0])
	var in_list_index = bank_paths.find(item)
	var boundary = current_bank_paths.size() - 1 if is_down else 0
	if in_list_index == boundary:
		return
	var new_index = in_list_index + 1 if is_down else in_list_index - 1
	bank_paths.remove_at(in_list_index)
	bank_paths.insert(new_index, item)
	last_selected_index = new_index
	emit_changed(path_property_name, bank_paths)


================================================
FILE: demo/addons/fmod/tool/property_editors/FmodBankPathEditorProperty.gd.uid
================================================
uid://cxyd4qioylvgr


================================================
FILE: demo/addons/fmod/tool/property_editors/FmodBankPathsPropertyEditorUi.tscn
================================================
[gd_scene load_steps=2 format=3 uid="uid://dtlwk8wdeal3h"]

[ext_resource type="Texture2D" uid="uid://o2chsr07oeqs" path="res://addons/fmod/icons/bank_icon.svg" id="1_11c48"]

[node name="FmodBankPathsPropertyEditorUi" type="VBoxContainer"]
offset_right = 92.0
offset_bottom = 43.0
size_flags_horizontal = 3
size_flags_vertical = 3

[node name="HBoxContainer" type="HBoxContainer" parent="."]
layout_mode = 2

[node name="AddButton" type="Button" parent="HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "+"
icon = ExtResource("1_11c48")
icon_alignment = 2

[node name="RemoveButton" type="Button" parent="HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "-"

[node name="VSeparator" type="VSeparator" parent="HBoxContainer"]
layout_mode = 2

[node name="UpButton" type="Button" parent="HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "↑"

[node name="DownButton" type="Button" parent="HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "↓"

[node name="BankList" type="ItemList" parent="."]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
auto_height = true

[node name="HBoxContainer2" type="HBoxContainer" parent="."]
layout_mode = 2

[node name="ManualAddLineEdit" type="LineEdit" parent="HBoxContainer2"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3

[node name="ManualAddButton" type="Button" parent="HBoxContainer2"]
unique_name_in_owner = true
layout_mode = 2
text = "+"


================================================
FILE: demo/addons/fmod/tool/property_editors/FmodEventEditorProperty.gd
================================================
@tool class_name FmodEventEditorProperty extends FmodPathEditorProperty


static var EVENT_PARAMETER_PREFIX_FOR_PROPERTIES = "fmod_parameters"

var former_event_description: FmodEventDescription

func _update_property():
	super()
	if get_edited_object().event_name == "":
		return
	_update_parameters()
	var event_description: FmodEventDescription = FmodServer.get_event_from_guid(get_edited_object().event_guid)
	
	if event_description == null:
		event_description = FmodServer.get_event(get_edited_object().event_name)
	
	former_event_description = event_description

func _set_path_and_guid(path: String, guid: String):
	super(path, guid)
	if get_edited_object().event_name == "":
		return
	_update_parameters()
	former_event_description = FmodServer.get_event_from_guid(get_edited_object().event_guid)

func _update_parameters():
	var event_description: FmodEventDescription = FmodServer.get_event_from_guid(get_edited_object().event_guid)
	
	if event_description == null:
		return
	
	if former_event_description != null and event_description != former_event_description:
		get_edited_object().tool_remove_all_parameters()
	
	var map_to_property_name = func map_to_property_name(dict: Dictionary):
			return dict["name"]
	var filter_fmod_parameter_property = func filter_fmod_parameter_property(parameter_name: String):
		return parameter_name.begins_with(EVENT_PARAMETER_PREFIX_FOR_PROPERTIES)
	
	var filter_property_id = func filter_property_id(property: String):
		return property.ends_with("/id")
	var existing_property_ids = get_edited_object().get_property_list().map(map_to_property_name).filter(filter_fmod_parameter_property).filter(filter_property_id)
	
	var map_property_name_to_parameter_name = func map_property_name_to_parameter_name(parameter: String):
		return parameter.split("/")[1]
	var existing_parameter_names = existing_property_ids.map(map_property_name_to_parameter_name)
	
	var map_property_id_to_parameter_id_value = func map_property_id_to_parameter_id_value(property: String):
		return get_edited_object()[property]
	var existing_parameter_ids = existing_property_ids.map(map_property_id_to_parameter_id_value)
	
	var property_matching = existing_parameter_ids.map(func(id): return false)
	
	for param: FmodParameterDescription in event_description.get_parameters():
		if param.is_global() or param.is_automatic() or param.is_read_only():
			continue
		
		var parameter_name = param.get_name()
		var parameter_id_param = "%s/%s/id" % [EVENT_PARAMETER_PREFIX_FOR_PROPERTIES, parameter_name]
		var parameter_value_param = "%s/%s" % [EVENT_PARAMETER_PREFIX_FOR_PROPERTIES, parameter_name]
		var parameter_variant_type = "%s/%s/variant_type" % [EVENT_PARAMETER_PREFIX_FOR_PROPERTIES, parameter_name]
		var parameter_labels = "%s/%s/labels" % [EVENT_PARAMETER_PREFIX_FOR_PROPERTIES, parameter_name]
		
		var existing_property_name_index = existing_property_ids.find(parameter_id_param)
		var are_properties_already_in_node = existing_property_name_index != -1
		
		var parameter_id = param.get_id()
		
		var variant_type: Variant.Type = TYPE_FLOAT
		var default_value = param.get_default_value()
		var minimum_value = param.get_minimum()
		var maximum_value = param.get_maximum()
		if param.is_labeled():
			variant_type = TYPE_STRING
			default_value = event_description.get_parameter_label_by_id(parameter_id, default_value)
			minimum_value = event_description.get_parameter_label_by_id(parameter_id, minimum_value)
			maximum_value = event_description.get_parameter_label_by_id(parameter_id, maximum_value)
		elif param.is_discrete():
			variant_type = TYPE_INT
			default_value = int(default_value)
			minimum_value = int(minimum_value)
			maximum_value = int(maximum_value)
		
		if are_properties_already_in_node:
			property_matching[existing_property_name_index] = existing_parameter_ids[existing_property_name_index] == parameter_id
		
		if not are_properties_already_in_node or get_edited_object()[parameter_id_param] == null:
			get_edited_object()[parameter_id_param] = parameter_id
		if not are_properties_already_in_node or get_edited_object()[parameter_value_param] == null:
			get_edited_object()[parameter_value_param] = default_value
		if not are_properties_already_in_node or get_edited_object()[parameter_variant_type] == null:
			get_edited_object()[parameter_variant_type] = variant_type
		if param.is_labeled() and (not are_properties_already_in_node or get_edited_object()[parameter_labels] == null):
			get_edited_object()[parameter_labels] = event_description.get_parameter_labels_by_id(parameter_id)
	
	for i in property_matching.size():
		if not property_matching[i]:
			get_edited_object().tool_remove_parameter(existing_parameter_ids[i])
	
	get_edited_object().notify_property_list_changed()


================================================
FILE: demo/addons/fmod/tool/property_editors/FmodEventEditorProperty.gd.uid
================================================
uid://b32x60k0th8td


================================================
FILE: demo/addons/fmod/tool/property_editors/FmodEventEditorProperty.tscn
================================================
[gd_scene load_steps=3 format=3 uid="uid://cowfthogh1n7i"]

[ext_resource type="PackedScene" uid="uid://cujo3xq0erren" path="res://addons/fmod/tool/property_editors/FmodPathEditorProperty.tscn" id="1_xvpec"]
[ext_resource type="Script" uid="uid://b32x60k0th8td" path="res://addons/fmod/tool/property_editors/FmodEventEditorProperty.gd" id="2_nkhkm"]

[node name="FmodEventEditorProperty" instance=ExtResource("1_xvpec")]
script = ExtResource("2_nkhkm")


================================================
FILE: demo/addons/fmod/tool/property_editors/FmodGuidAndPathPropertyEditorUi.gd
================================================
@tool class_name FmodGuidAndPathPropertyEditorUi extends HBoxContainer


func set_callables(window_callable: Callable, path_callable: Callable, guid_callable: Callable):
	%EventExplorerButton.pressed.connect(window_callable)
	%PathLineEdit.text_changed.connect(path_callable)
	%GuidLineEdit.text_changed.connect(guid_callable)

func set_icon(icon: Texture2D):
	%EventExplorerButton.icon = icon


================================================
FILE: demo/addons/fmod/tool/property_editors/FmodGuidAndPathPropertyEditorUi.gd.uid
================================================
uid://3xn18ci172v4


================================================
FILE: demo/addons/fmod/tool/property_editors/FmodGuidAndPathPropertyEditorUi.tscn
================================================
[gd_scene load_steps=3 format=3 uid="uid://hy04frgfhtgu"]

[ext_resource type="Script" uid="uid://3xn18ci172v4" path="res://addons/fmod/tool/property_editors/FmodGuidAndPathPropertyEditorUi.gd" id="1_eao7t"]
[ext_resource type="Texture2D" uid="uid://cmpgmbn3y4svl" path="res://addons/fmod/icons/event_icon.svg" id="1_kuu6i"]

[node name="FmodGuidAndPathPropertyEditorUi" type="HBoxContainer"]
offset_right = 1152.0
offset_bottom = 66.0
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource("1_eao7t")

[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 2
size_flags_horizontal = 3

[node name="PathLineEdit" type="LineEdit" parent="VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2

[node name="GuidLineEdit" type="LineEdit" parent="VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2

[node name="EventExplorerButton" type="Button" parent="."]
unique_name_in_owner = true
layout_mode = 2
icon = ExtResource("1_kuu6i")


================================================
FILE: demo/addons/fmod/tool/property_editors/FmodPathEditorProperty.gd
================================================
@tool class_name FmodPathEditorProperty extends EditorProperty

var ui: Control
var guid_property: String
var path_property: String
var regex := RegEx.new()

var default_line_edit_modulate: Color

func initialize(open_project_explorer_callable: Callable, path_prop: String, guid_prop: String):
	regex.compile("{\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}}")
	guid_property = guid_prop
	path_property = path_prop
	var guid_and_path_ui: FmodGuidAndPathPropertyEditorUi = %FmodGuidAndPathPropertyEditorUi
	
	default_line_edit_modulate = guid_and_path_ui.get_node("%GuidLineEdit").modulate
	
	var open_project_explorer_event = func open_project_explorer_event():
		open_project_explorer_callable.call(self._set_path_and_guid)
	guid_and_path_ui.set_callables(open_project_explorer_event, _set_path, _set_guid)

func _update_property():
	var guid_and_path_ui = %FmodGuidAndPathPropertyEditorUi
	guid_and_path_ui.get_node("%PathLineEdit").text = get_edited_object()[path_property]
	guid_and_path_ui.get_node("%GuidLineEdit").text = get_edited_object()[guid_property]

func _set_path(path: String):
	emit_changed(path_property, path)

func _set_guid(guid: String):
	var line_edit := %FmodGuidAndPathPropertyEditorUi.get_node("%GuidLineEdit") as LineEdit
	if not regex.search(guid):
		line_edit.modulate = Color.RED
		return
	line_edit.modulate = default_line_edit_modulate
	emit_changed(guid_property, guid)

func _set_path_and_guid(path: String, guid: String):
	_set_path(path)
	_set_guid(guid)


================================================
FILE: demo/addons/fmod/tool/property_editors/FmodPathEditorProperty.gd.uid
================================================
uid://qshng8csi2fr


================================================
FILE: demo/addons/fmod/tool/property_editors/FmodPathEditorProperty.tscn
================================================
[gd_scene load_steps=3 format=3 uid="uid://cujo3xq0erren"]

[ext_resource type="Script" uid="uid://qshng8csi2fr" path="res://addons/fmod/tool/property_editors/FmodPathEditorProperty.gd" id="1_4e4vx"]
[ext_resource type="PackedScene" uid="uid://hy04frgfhtgu" path="res://addons/fmod/tool/property_editors/FmodGuidAndPathPropertyEditorUi.tscn" id="2_nvtqg"]

[node name="FmodPathEditorProperty" type="EditorProperty"]
script = ExtResource("1_4e4vx")

[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 2

[node name="FmodGuidAndPathPropertyEditorUi" parent="VBoxContainer" instance=ExtResource("2_nvtqg")]
unique_name_in_owner = true
layout_mode = 2


================================================
FILE: demo/addons/fmod/tool/ui/EventParametersDisplay.gd
================================================
@tool class_name EventParametersDisplay extends ScrollContainer

static var parameter_display_scene: PackedScene = load("res://addons/fmod/tool/ui/ParameterDisplay.tscn")

func set_fmod_event(event: FmodEventDescription) -> bool: # returns false if there were no parameters
	for child in %ParameterDisplaysContainer.get_children():
		%ParameterDisplaysContainer.remove_child(child)
		child.queue_free()
	
	var event_parameters: Array = event.get_parameters()
	if event_parameters:
		show()
		for parameter : FmodParameterDescription in event_parameters:
			var parameter_display: ParameterDisplay = parameter_display_scene.instantiate()
			parameter_display.set_event_description(event)
			parameter_display.set_parameter(parameter)
			if %ParameterDisplaysContainer.get_child_count() > 0:
				%ParameterDisplaysContainer.add_child(HSeparator.new())
			%ParameterDisplaysContainer.add_child(parameter_display)
		return true # we had parameters to show!
	else:
		return false # no parameters to visualise


================================================
FILE: demo/addons/fmod/tool/ui/EventParametersDisplay.gd.uid
================================================
uid://7relkis52fsu


================================================
FILE: demo/addons/fmod/tool/ui/EventParametersDisplay.tscn
================================================
[gd_scene load_steps=2 format=3 uid="uid://cppeyr1ke5wre"]

[ext_resource type="Script" uid="uid://7relkis52fsu" path="res://addons/fmod/tool/ui/EventParametersDisplay.gd" id="1_2l58q"]

[node name="EventParametersDisplay" type="ScrollContainer"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource("1_2l58q")

[node name="ParameterDisplaysContainer" type="VBoxContainer" parent="."]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3


================================================
FILE: demo/addons/fmod/tool/ui/EventParametersWindow.tscn
================================================
[gd_scene load_steps=2 format=3 uid="uid://skp8awewyl85"]

[ext_resource type="PackedScene" uid="uid://cppeyr1ke5wre" path="res://addons/fmod/tool/ui/EventParametersDisplay.tscn" id="1_clkxg"]

[node name="EventParametersWindow" type="Window"]

[node name="EventParametersDisplay" parent="." instance=ExtResource("1_clkxg")]


================================================
FILE: demo/addons/fmod/tool/ui/EventPlayControls.gd
================================================
@tool
extends PanelContainer

@export var play_button : Button
@export var stop_button : Button
@export var fade_out_toggle : CheckButton
var event_instance : FmodEvent

func _ready() -> void:
	hide()
	play_button.icon = EditorInterface.get_editor_theme().get_icon("Play", "EditorIcons")
	stop_button.icon = EditorInterface.get_editor_theme().get_icon("Stop", "EditorIcons")
	play_button.pressed.connect(on_play_button_pressed)
	stop_button.pressed.connect(on_stop_button_pressed)


func set_fmod_event(_event_description : FmodEventDescription) -> void:
	stop_and_release_instance() # always stop and release if a previous one is active
	event_instance = FmodServer.create_event_instance_with_guid(_event_description.get_guid())
	show()
	
	
func play_event() -> void:
	if event_instance:
		event_instance.start()
	
	
func stop_event() -> void:
	if event_instance:
		var stop_mode : int = FmodServer.FMOD_STUDIO_STOP_IMMEDIATE
		if fade_out_toggle.button_pressed:
			stop_mode = FmodServer.FMOD_STUDIO_STOP_ALLOWFADEOUT
			
		event_instance.stop(stop_mode)
	
	
func _exit_tree() -> void:
	stop_and_release_instance()
	
	
func stop_and_release_instance() -> void:
	if event_instance:
		event_instance.stop(0)
		event_instance.release()


func on_play_button_pressed() -> void:
	play_event()
	
	
func on_stop_button_pressed() -> void:
	stop_event()


================================================
FILE: demo/addons/fmod/tool/ui/EventPlayControls.gd.uid
================================================
uid://vgmq7hfrbddw


================================================
FILE: demo/addons/fmod/tool/ui/FmodBankExplorer.gd
================================================
@tool class_name FmodBankExplorer extends Window

enum ToDisplayFlags {
	BUSES = 1,
	VCA = 2,
	EVENTS = 4
}

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

var banks: Array = Array()

var flags: int = 0
var search: String = ""

func reset_search():
	%SearchField.text = ""
	search = ""

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

	generate_tree()
	%RefreshBanksButton.pressed.connect(on_refresh_banks_button_pressed)


func regenerate_tree(callable: Callable = Callable()):
	tree.clear()
	generate_tree(callable)

func generate_tree(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

	var root_item := tree.create_item()
	root_item.set_text(0, "Fmod objects")
	root_item.set_icon(0, _fmod_icon)

	var has_many_flags = (flags & (flags - 1)) != 0

	for bank in FmodServer.get_all_banks():
		var fmod_bank := bank as FmodBank

		var buses := fmod_bank.get_bus_list()
		var vcas := fmod_bank.get_vca_list()
		var events := fmod_bank.get_description_list()

		if search.is_empty():
			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 flags & ToDisplayFlags.BUSES and buses.size() != 0:
				buses.sort_custom(sort_by_path)
				if has_many_flags:
					var buses_item := tree.create_item(bank_item)
					buses_item.set_text(0, "Buses")
					buses_item.set_icon(0, _bus_icon)
					_add_elements_as_tree(buses, buses_item)
				else:
					_add_elements_as_tree(buses, bank_item)

			if flags & ToDisplayFlags.VCA and vcas.size() != 0:
				vcas.sort_custom(sort_by_path)
				if has_many_flags:
					var vca_item := tree.create_item(bank_item)
					vca_item.set_text(0, "VCAs")
					vca_item.set_icon(0, _vca_icon)
					_add_elements_as_tree(vcas, vca_item)
				else:
					_add_elements_as_tree(vcas, bank_item)

			if flags & ToDisplayFlags.EVENTS and events.size() != 0:
				events.sort_custom(sort_by_path)
				if has_many_flags:
					var events_item := tree.create_item(bank_item)
					events_item.set_text(0, "Events")
					events_item.set_icon(0, _event_icon)
					_add_elements_as_tree(events, events_item)
				else:
					_add_elements_as_tree(events, bank_item)

		else:
			if flags & ToDisplayFlags.BUSES:
				_add_elements_as_items(buses, root_item)
			if flags & ToDisplayFlags.VCA:
				_add_elements_as_items(vcas, root_item)
			if flags & ToDisplayFlags.EVENTS:
				_add_elements_as_items(events, root_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_items(elements: Array, parent: TreeItem):
		for element in elements:
			var full_path: String = element.get_path()
			if not full_path.containsn(search):
				continue

			var child := tree.create_item(parent)
			var name := full_path.rsplit("/")[-1]
			child.set_text(0, name)
			child.set_metadata(0, element)
			child.set_icon(0, _get_icon_for_fmod_path(full_path))

func _add_elements_as_tree(elements: Array, parent: TreeItem):
	var nodes := { "": parent }

	for element in elements:
		var full_path: String = element.get_path()
		var parts := full_path.split("/")
		# Drop the “type:” prefix
		if parts.size() > 0:
			parts.remove_at(0)

		# Walk each segment in turn, building a running “key”
		var key := ""
		for i in range(parts.size()):
			var name = parts[i]
			if full_path == "bus:/":
				name = "Master"
			if key == "":
				key = name
			else:
				key = key + "/" + name

			# If we haven’t created this node yet, do so now
			if not nodes.has(key):
				var root_and_name := key.rsplit("/", false, 1)
				var parent_key: String = ""
				if root_and_name.size() == 2:
					parent_key = root_and_name[0]
				var parent_item = nodes[parent_key]
				var child := tree.create_item(parent_item)
				child.set_text(0, name)
				nodes[key] = child

			# If this is the final segment, attach the metadata & icon
			if i == parts.size() - 1:
				var leaf = nodes[key]
				leaf.set_metadata(0, element)
				leaf.set_icon(0, _get_icon_for_fmod_path(full_path))

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
	banks.clear()
	tree.clear()
	FmodBankDatabase.reload_all_banks()
	generate_tree()

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


func _on_text_edit_text_submitted(new_text: String) -> void:
	search = new_text
	regenerate_tree()


================================================
FILE: demo/addons/fmod/tool/ui/FmodBankExplorer.gd.uid
================================================
uid://b5xgbibc3amtk


================================================
FILE: demo/addons/fmod/tool/ui/FmodBankExplorer.tscn
================================================
[gd_scene load_steps=17 format=3 uid="uid://nr38urn226al"]

[ext_resource type="Script" uid="uid://b5xgbibc3amtk" path="res://addons/fmod/tool/ui/FmodBankExplorer.gd" id="1_ekqus"]
[ext_resource type="Script" uid="uid://vgmq7hfrbddw" path="res://addons/fmod/tool/ui/EventPlayControls.gd" id="2_mleop"]
[ext_resource type="PackedScene" uid="uid://cppeyr1ke5wre" path="res://addons/fmod/tool/ui/EventParametersDisplay.tscn" id="2_uoyg8"]

[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_potss"]
bg_color = Color(0.21176471, 0.23921569, 0.2901961, 1)

[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_piloo"]
bg_color = Color(0.21176471, 0.23921569, 0.2901961, 1)

[sub_resource type="Theme" id="Theme_02ixt"]
Button/styles/normal = SubResource("StyleBoxFlat_potss")
LineEdit/styles/normal = SubResource("StyleBoxFlat_piloo")

[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_wrr0m"]
bg_color = Color(0, 0, 0, 0.247059)
border_width_left = 1
border_width_top = 1
border_width_right = 1
border_width_bottom = 1
border_color = Color(1, 1, 1, 0.207843)
corner_radius_top_left = 5
corner_radius_top_right = 5
corner_radius_bottom_right = 5
corner_radius_bottom_left = 5

[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_2pbsy"]

[sub_resource type="LabelSettings" id="LabelSettings_3jkpq"]
font_size = 18

[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_0awfk"]
bg_color = Color(0, 0, 0, 0.14902)
border_width_left = 1
border_width_top = 1
border_width_right = 1
border_width_bottom = 1
border_color = Color(0.8, 0.8, 0.8, 0.145098)
corner_radius_top_left = 5
corner_radius_top_right = 5
corner_radius_bottom_right = 5
corner_radius_bottom_left = 5

[sub_resource type="LabelSettings" id="LabelSettings_d4isr"]

[sub_resource type="DPITexture" id="DPITexture_potss"]
_source = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\"><path fill=\"#e0e0e0\" d=\"M2 1a1 1 0 0 0-1 1v9a1 1 0 0 0 1 1h1V3h9V2a1 1 0 0 0-1-1zm3 3a1 1 0 0 0-1 1v9a1 1 0 0 0 1 1h9a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1zm1 2h7v7H6z\"/></svg>
"
base_scale = 1.25
color_map = {
Color(1, 0.37254903, 0.37254903, 1): Color(1, 0.47, 0.42, 1),
Color(0.37254903, 1, 0.5921569, 1): Color(0.45, 0.95, 0.5, 1),
Color(1, 0.8666667, 0.39607844, 1): Color(1, 0.87, 0.4, 1)
}

[sub_resource type="DPITexture" id="DPITexture_piloo"]
_source = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\"><path fill=\"#e0e0e0\" d=\"M4 12a1 1 0 0 0 1.555.832l6-4a1 1 0 0 0 0-1.664l-6-4A1 1 0 0 0 4 4z\"/></svg>
"
base_scale = 1.25
color_map = {
Color(1, 0.37254903, 0.37254903, 1): Color(1, 0.47, 0.42, 1),
Color(0.37254903, 1, 0.5921569, 1): Color(0.45, 0.95, 0.5, 1),
Color(1, 0.8666667, 0.39607844, 1): Color(1, 0.87, 0.4, 1)
}

[sub_resource type="DPITexture" id="DPITexture_02ixt"]
_source = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\"><rect width=\"10\" height=\"10\" x=\"3\" y=\"3\" fill=\"#e0e0e0\" rx=\"1\"/></svg>
"
base_scale = 1.25
color_map = {
Color(1, 0.37254903, 0.37254903, 1): Color(1, 0.47, 0.42, 1),
Color(0.37254903, 1, 0.5921569, 1): Color(0.45, 0.95, 0.5, 1),
Color(1, 0.8666667, 0.39607844, 1): Color(1, 0.87, 0.4, 1)
}

[sub_resource type="InputEventKey" id="InputEventKey_w47tf"]
device = -1
keycode = 4194305

[sub_resource type="Shortcut" id="Shortcut_rarey"]
events = [SubResource("InputEventKey_w47tf")]

[node name="FmodBankExplorer" type="Window"]
oversampling_override = 1.0
title = "Fmod banks explorer"
initial_position = 2
size = Vector2i(1280, 673)
script = ExtResource("1_ekqus")

[node name="BGPanel" type="Panel" parent="."]
unique_name_in_owner = true
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

[node name="WindowMargin" type="MarginContainer" parent="."]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = SubResource("Theme_02ixt")
theme_override_constants/margin_left = 16
theme_override_constants/margin_top = 16
theme_override_constants/margin_right = 16
theme_override_constants/margin_bottom = 16

[node name="VBoxContainer" type="VBoxContainer" parent="WindowMargin"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3

[node name="TopPanel" type="PanelContainer" parent="WindowMargin/VBoxContainer"]
custom_minimum_size = Vector2(0, 42.315)
layout_mode = 2

[node name="HBoxContainer" type="HBoxContainer" parent="WindowMargin/VBoxContainer/TopPanel"]
layout_mode = 2
alignment = 2

[node name="SearchField" type="LineEdit" parent="WindowMargin/VBoxContainer/TopPanel/HBoxContainer"]
unique_name_in_owner = true
custom_minimum_size = Vector2(200, 0)
layout_mode = 2
size_flags_horizontal = 2
placeholder_text = "Search.."
context_menu_enabled = false

[node name="RefreshBanksButton" type="Button" parent="WindowMargin/VBoxContainer/TopPanel/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "Refresh Banks"

[node name="BaseColorPanel" type="PanelContainer" parent="WindowMargin/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
theme_override_styles/panel = SubResource("StyleBoxFlat_wrr0m")

[node name="MarginContainer" type="MarginContainer" parent="WindowMargin/VBoxContainer/BaseColorPanel"]
layout_mode = 2
size_flags_vertical = 3
theme_override_constants/margin_left = 8
theme_override_constants/margin_top = 8
theme_override_constants/margin_right = 8
theme_override_constants/margin_bottom = 8

[node name="HSplitContainer" type="HSplitContainer" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer"]
layout_mode = 2

[node name="Tree" type="Tree" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
size_flags_stretch_ratio = 0.54
theme_override_styles/panel = SubResource("StyleBoxEmpty_2pbsy")
hide_root = true

[node name="MarginContainer" type="MarginContainer" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/margin_left = 8
theme_override_constants/margin_top = 8
theme_override_constants/margin_right = 8
theme_override_constants/margin_bottom = 8

[node name="RightPanelContent" type="VBoxContainer" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3

[node name="PathsLabel" type="Label" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent"]
visible = false
layout_mode = 2
size_flags_vertical = 1
text = "ID:"
label_settings = SubResource("LabelSettings_3jkpq")
justification_flags = 35

[node name="PathsBG" type="PanelContainer" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent"]
unique_name_in_owner = true
visible = false
layout_mode = 2
size_flags_horizontal = 3
theme_override_styles/panel = SubResource("StyleBoxFlat_0awfk")

[node name="MarginContainer" type="MarginContainer" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/PathsBG"]
layout_mode = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10

[node name="PathContainer" type="HBoxContainer" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/PathsBG/MarginContainer"]
layout_mode = 2

[node name="TitleLabelContainer" type="VBoxContainer" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/PathsBG/MarginContainer/PathContainer"]
layout_mode = 2

[node name="PathTitleLabel" type="Label" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/PathsBG/MarginContainer/PathContainer/TitleLabelContainer"]
layout_mode = 2
size_flags_vertical = 6
text = "Path:"
label_settings = SubResource("LabelSettings_d4isr")

[node name="GuidTitleLabel" type="Label" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/PathsBG/MarginContainer/PathContainer/TitleLabelContainer"]
layout_mode = 2
size_flags_vertical = 6
text = "GUID: "
label_settings = SubResource("LabelSettings_d4isr")

[node name="ValueContainer" type="VBoxContainer" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/PathsBG/MarginContainer/PathContainer"]
layout_mode = 2
size_flags_horizontal = 3

[node name="PathLabel" type="Label" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/PathsBG/MarginContainer/PathContainer/ValueContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 6
text = "asdfasdfasdfasdf"

[node name="CopyPathLabel" type="Button" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/PathsBG/MarginContainer/PathContainer/ValueContainer/PathLabel"]
visible = false
layout_mode = 1
anchors_preset = 6
anchor_left = 1.0
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
offset_left = 5.57001
offset_top = -15.5
offset_right = 36.57
offset_bottom = 15.5
grow_horizontal = 0
grow_vertical = 2
icon = SubResource("DPITexture_potss")

[node name="GuidLabel" type="Label" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/PathsBG/MarginContainer/PathContainer/ValueContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 6
text = "asdfasdf"
vertical_alignment = 1

[node name="CopyGuidLabel" type="Button" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/PathsBG/MarginContainer/PathContainer/ValueContainer/GuidLabel"]
visible = false
layout_mode = 1
anchors_preset = 6
anchor_left = 1.0
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
offset_left = 6.095
offset_top = -15.5
offset_right = 37.095
offset_bottom = 15.5
grow_horizontal = 0
grow_vertical = 2
icon = SubResource("DPITexture_potss")

[node name="ParametersLabel" type="Label" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent"]
unique_name_in_owner = true
visible = false
custom_minimum_size = Vector2(0, 45)
layout_mode = 2
text = "Parameters:"
label_settings = SubResource("LabelSettings_3jkpq")
vertical_alignment = 2

[node name="ParametersContainer" type="PanelContainer" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent"]
unique_name_in_owner = true
visible = false
layout_mode = 2
size_flags_vertical = 3
theme_override_styles/panel = SubResource("StyleBoxFlat_0awfk")

[node name="MarginContainer" type="MarginContainer" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/ParametersContainer"]
layout_mode = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10

[node name="EventParametersDisplay" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/ParametersContainer/MarginContainer" instance=ExtResource("2_uoyg8")]
unique_name_in_owner = true
layout_mode = 2

[node name="EventPlayControls" type="PanelContainer" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent" node_paths=PackedStringArray("play_button", "stop_button", "fade_out_toggle")]
unique_name_in_owner = true
visible = false
custom_minimum_size = Vector2(0, 55.44)
layout_mode = 2
size_flags_vertical = 10
size_flags_stretch_ratio = 0.1
theme_override_styles/panel = SubResource("StyleBoxFlat_0awfk")
script = ExtResource("2_mleop")
play_button = NodePath("MarginContainer/HBoxContainer/PlayEventButton")
stop_button = NodePath("MarginContainer/HBoxContainer/StopEventButton")
fade_out_toggle = NodePath("MarginContainer/HBoxContainer/FadeoutToggle")

[node name="MarginContainer" type="MarginContainer" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/EventPlayControls"]
layout_mode = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10

[node name="HBoxContainer" type="HBoxContainer" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/EventPlayControls/MarginContainer"]
layout_mode = 2

[node name="PlayEventButton" type="Button" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/EventPlayControls/MarginContainer/HBoxContainer"]
layout_mode = 2
text = "Play"
icon = SubResource("DPITexture_piloo")

[node name="StopEventButton" type="Button" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/EventPlayControls/MarginContainer/HBoxContainer"]
layout_mode = 2
text = "Stop"
icon = SubResource("DPITexture_02ixt")

[node name="FadeoutToggle" type="CheckButton" parent="WindowMargin/VBoxContainer/BaseColorPanel/MarginContainer/HSplitContainer/MarginContainer/RightPanelContent/EventPlayControls/MarginContainer/HBoxContainer"]
layout_mode = 2
text = "Allow fade out"

[node name="MarginContainer" type="MarginContainer" parent="WindowMargin/VBoxContainer"]
layout_mode = 2
theme_override_constants/margin_top = 8

[node name="HBoxContainer" type="HBoxContainer" parent="WindowMargin/VBoxContainer/MarginContainer"]
layout_mode = 2
alignment = 1

[node name="MarginContainer2" type="MarginContainer" parent="WindowMargin/VBoxContainer/MarginContainer/HBoxContainer"]
layout_mode = 2
theme_override_constants/margin_left = 8
theme_override_constants/margin_right = 8

[node name="SelectButton" type="Button" parent="WindowMargin/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer2"]
unique_name_in_owner = true
visible = false
layout_mode = 2
size_flags_horizontal = 4
text = "Select"

[node name="MarginContainer" type="MarginContainer" parent="WindowMargin/VBoxContainer/MarginContainer/HBoxContainer"]
layout_mode = 2
theme_override_constants/margin_left = 8
theme_override_constants/margin_right = 8

[node name="CloseButton" type="Button" parent="WindowMargin/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 4
shortcut = SubResource("Shortcut_rarey")
text = "Close"

[connection signal="text_submitted" from="WindowMargin/VBoxContainer/TopPanel/HBoxContainer/SearchField" to="." method="_on_text_edit_text_submitted"]


================================================
FILE: demo/addons/fmod/tool/ui/ParameterDisplay.gd
================================================
@tool class_name ParameterDisplay extends MarginContainer

var event_description: FmodEventDescription
var parameter: FmodParameterDescription

func set_event_description(p_event_description: FmodEventDescription):
	event_description = p_event_description

func set_parameter(p_parameter: FmodParameterDescription):
	show()
	parameter = p_parameter

func display_value_selector(should: bool):
	%ValueSetterContainer.visible = should

func _ready():
	if parameter == null:
		hide()
		return
	var minimum_value = parameter.get_minimum()
	var maximum_value = parameter.get_maximum()
	var default_value = parameter.get_default_value()
	
	var copy_icon : Texture = EditorInterface.get_editor_theme().get_icon("ActionCopy", "EditorIcons")
	%NameCopyButton.icon = copy_icon
	%IdCopyButton.icon = copy_icon
	
	
	%NameLabel.text = parameter.get_name()
	%IdLabel.text = str(parameter.get_id())
	if parameter.is_labeled():
		%RangeTitle.text = "Values"
		var values_text = "["
		var is_first: bool = true
		for label: String in event_description.get_parameter_labels_by_id(parameter.get_id()):
			if not is_first:
				values_text += ", "
			values_text += label
			is_first = false
		values_text += "]"
		%RangeLabel.text = values_text
	else:
		%RangeLabel.text = "[%s, %s]" % [minimum_value, maximum_value]
	%DefaultValueLabel.text = str(default_value)
	%NameCopyButton.pressed.connect(_on_copy_name_button)
	%IdCopyButton.pressed.connect(_on_copy_id_button)
	%BackToDefaultButton.pressed.connect(_on_default_value_button)
	
	%ValueSlider.min_value = minimum_value
	%ValueSlider.max_value = maximum_value
	%ValueSlider.value = default_value
	
	_on_slider_value_changed(%ValueSlider.value)
	%ValueSlider.value_changed.connect(_on_slider_value_changed)

func _on_copy_name_button():
	DisplayServer.clipboard_set(%NameLabel.text)

func _on_copy_id_button():
	DisplayServer.clipboard_set(%IdLabel.text)

func _on_default_value_button():
	%ValueSlider.value = parameter.get_default_value()

func _on_slider_value_changed(value: float):
	%CurrentValueLabel.text = str(value)


================================================
FILE: demo/addons/fmod/tool/ui/ParameterDisplay.gd.uid
================================================
uid://ve6g43nb1hdd


================================================
FILE: demo/addons/fmod/tool/ui/ParameterDisplay.tscn
================================================
[gd_scene load_steps=2 format=3 uid="uid://bfdldojk5i6u3"]

[ext_resource type="Script" uid="uid://ve6g43nb1hdd" path="res://addons/fmod/tool/ui/ParameterDisplay.gd" id="1_fxyw8"]

[node name="ParameterDisplay" type="MarginContainer"]
visible = false
offset_right = 168.0
offset_bottom = 160.0
size_flags_horizontal = 3
theme_override_constants/margin_left = 4
theme_override_constants/margin_top = 4
theme_override_constants/margin_right = 4
theme_override_constants/margin_bottom = 4
script = ExtResource("1_fxyw8")

[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 2

[node name="VBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
layout_mode = 2

[node name="TitleContainer" type="VBoxContainer" parent="VBoxContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 20

[node name="NameTitle" type="Label" parent="VBoxContainer/VBoxContainer/TitleContainer"]
layout_mode = 2
size_flags_vertical = 10
text = "Name: "

[node name="IdTitle" type="Label" parent="VBoxContainer/VBoxContainer/TitleContainer"]
layout_mode = 2
size_flags_vertical = 10
text = "ID: "

[node name="RangeTitle" type="Label" parent="VBoxContainer/VBoxContainer/TitleContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 10
text = "Range: "

[node name="DefaultValueTitle" type="Label" parent="VBoxContainer/VBoxContainer/TitleContainer"]
layout_mode = 2
size_flags_vertical = 10
text = "Default value: "

[node name="ContentContainer" type="VBoxContainer" parent="VBoxContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 20

[node name="NameLabel" type="Label" parent="VBoxContainer/VBoxContainer/ContentContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 10

[node name="NameCopyButton" type="Button" parent="VBoxContainer/VBoxContainer/ContentContainer/NameLabel"]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 6
anchor_left = 1.0
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
offset_left = 9.0
offset_top = -15.5
offset_right = 40.0
offset_bottom = 15.5
grow_horizontal = 0
grow_vertical = 2
size_flags_vertical = 10

[node name="IdLabel" type="Label" parent="VBoxContainer/VBoxContainer/ContentContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 10

[node name="IdCopyButton" type="Button" parent="VBoxContainer/VBoxContainer/ContentContainer/IdLabel"]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 6
anchor_left = 1.0
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
offset_left = 9.0
offset_top = -15.5
offset_right = 40.0
offset_bottom = 15.5
grow_horizontal = 0
grow_vertical = 2
size_flags_vertical = 10

[node name="RangeLabel" type="Label" parent="VBoxContainer/VBoxContainer/ContentContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 10

[node name="DefaultValueLabel" type="Label" parent="VBoxContainer/VBoxContainer/ContentContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 10

[node name="ValueSetterContainer" type="VBoxContainer" parent="VBoxContainer"]
unique_name_in_owner = true
visible = false
layout_mode = 2

[node name="HSeparator" type="HSeparator" parent="VBoxContainer/ValueSetterContainer"]
layout_mode = 2

[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/ValueSetterContainer"]
layout_mode = 2

[node name="Label" type="Label" parent="VBoxContainer/ValueSetterContainer/HBoxContainer"]
layout_mode = 2
text = "Set value: "

[node name="ValueSlider" type="HSlider" parent="VBoxContainer/ValueSetterContainer/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 4

[node name="BackToDefaultButton" type="Button" parent="VBoxContainer/ValueSetterContainer/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "Default"

[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer/ValueSetterContainer"]
layout_mode = 2

[node name="CurrentValueTitleLabel" type="Label" parent="VBoxContainer/ValueSetterContainer/HBoxContainer2"]
layout_mode = 2
text = "Current value: "

[node name="CurrentValueLabel" type="Label" parent="VBoxContainer/ValueSetterContainer/HBoxContainer2"]
unique_name_in_owner = true
layout_mode = 2

[node name="Button" type="Button" parent="VBoxContainer/ValueSetterContainer"]
layout_mode = 2
text = "Select"


================================================
FILE: demo/addons/fmod/tool/ui/TestFmodBankExplorer.tscn
================================================
[gd_scene load_steps=2 format=3 uid="uid://f4i35731qm63"]

[ext_resource type="PackedScene" uid="uid://nr38urn226al" path="res://addons/fmod/tool/ui/FmodBankExplorer.tscn" id="1_0ul6h"]

[node name="TestFmodBankExplorer" type="Node2D"]

[node name="FmodBankLoader" type="FmodBankLoader" parent="."]
bank_paths = ["res://assets/Banks/Master.strings.bank", "res://assets/Banks/Master.bank", "res://assets/Banks/Music.bank", "res://assets/Banks/Vehicles.bank"]

[node name="FmodBankExplorer" parent="FmodBankLoader" instance=ExtResource("1_0ul6h")]
initial_position = 0
position = Vector2i(0, 36)


================================================
FILE: demo/addons/gut/GutScene.gd
================================================
extends Node2D
# ##############################################################################
# This is a wrapper around the normal and compact gui controls and serves as
# the interface between gut.gd and the gui.  The GutRunner creates an instance
# of this and then this takes care of managing the different GUI controls.
# ##############################################################################
@onready var _normal_gui = $Normal
@onready var _compact_gui = $Compact

var gut = null :
	set(val):
		gut = val
		_set_gut(val)


func _ready():
	_normal_gui.switch_modes.connect(use_compact_mode.bind(true))
	_compact_gui.switch_modes.connect(use_compact_mode.bind(false))

	_normal_gui.set_title("GUT")
	_compact_gui.set_title("GUT")

	_normal_gui.align_right()
	_compact_gui.to_bottom_right()

	use_compact_mode(false)

	if(get_parent() == get_tree().root):
		_test_running_setup()

func _test_running_setup():
	set_font_size(100)
	_normal_gui.get_textbox().text = "hello world, how are you doing?"

# ------------------------
# Private
# ------------------------
func _set_gut(val):
	if(_normal_gui.get_gut() == val):
		return
	_normal_gui.set_gut(val)
	_compact_gui.set_gut(val)

	val.start_run.connect(_on_gut_start_run)
	val.end_run.connect(_on_gut_end_run)
	val.start_pause_before_teardown.connect(_on_gut_pause)
	val.end_pause_before_teardown.connect(_on_pause_end)

func _set_both_titles(text):
	_normal_gui.set_title(text)
	_compact_gui.set_title(text)


# ------------------------
# Events
# ------------------------
func _on_gut_start_run():
	_set_both_titles('Running')

func _on_gut_end_run():
	_set_both_titles('Finished')

func _on_gut_pause():
	_set_both_titles('-- Paused --')

func _on_pause_end():
	_set_both_titles('Running')


# ------------------------
# Public
# ------------------------
func get_textbox():
	return _normal_gui.get_textbox()


func set_font_size(new_size):
	var rtl = _normal_gui.get_textbox()

	rtl.set('theme_override_font_sizes/bold_italics_font_size', new_size)
	rtl.set('theme_override_font_sizes/bold_font_size', new_size)
	rtl.set('theme_override_font_sizes/italics_font_size', new_size)
	rtl.set('theme_override_font_sizes/normal_font_size', new_size)


func set_font(font_name):
	_set_all_fonts_in_rtl(_normal_gui.get_textbox(), font_name)


func _set_font(rtl, font_name, custom_name):
	if(font_name == null):
		rtl.remove_theme_font_override(custom_name)
	else:
		var font_path = 'res://addons/gut/fonts/' + font_name + '.ttf'
		if(FileAccess.file_exists(font_path)):
			var dyn_font = FontFile.new()
			dyn_font.load_dynamic_font('res://addons/gut/fonts/' + font_name + '.ttf')
			rtl.add_theme_font_override(custom_name, dyn_font)


func _set_all_fonts_in_rtl(rtl, base_name):
	if(base_name == 'Default'):
		_set_font(rtl, null, 'normal_font')
		_set_font(rtl, null, 'bold_font')
		_set_font(rtl, null, 'italics_font')
		_set_font(rtl, null, 'bold_italics_font')
	else:
		_set_font(rtl, base_name + '-Regular', 'normal_font')
		_set_font(rtl, base_name + '-Bold', 'bold_font')
		_set_font(rtl, base_name + '-Italic', 'italics_font')
		_set_font(rtl, base_name + '-BoldItalic', 'bold_italics_font')


func set_default_font_color(color):
	_normal_gui.get_textbox().set('custom_colors/default_color', color)


func set_background_color(color):
	_normal_gui.set_bg_color(color)


func use_compact_mode(should=true):
	_compact_gui.visible = should
	_normal_gui.visible = !should


func set_opacity(val):
	_normal_gui.modulate.a = val
	_compact_gui.modulate.a = val

func set_title(text):
	_set_both_titles(text)


================================================
FILE: demo/addons/gut/GutScene.gd.uid
================================================
uid://bw7tukh738kw1


================================================
FILE: demo/addons/gut/GutScene.tscn
================================================
[gd_scene load_steps=4 format=3 uid="uid://m28heqtswbuq"]

[ext_resource type="Script" uid="uid://bw7tukh738kw1" path="res://addons/gut/GutScene.gd" id="1_b4m8y"]
[ext_resource type="PackedScene" uid="uid://duxblir3vu8x7" path="res://addons/gut/gui/NormalGui.tscn" id="2_j6ywb"]
[ext_resource type="PackedScene" uid="uid://cnqqdfsn80ise" path="res://addons/gut/gui/MinGui.tscn" id="3_3glw1"]

[node name="GutScene" type="Node2D"]
script = ExtResource("1_b4m8y")

[node name="Normal" parent="." instance=ExtResource("2_j6ywb")]

[node name="Compact" parent="." instance=ExtResource("3_3glw1")]
offset_left = 5.0
offset_top = 273.0
offset_right = 265.0
offset_bottom = 403.0


================================================
FILE: demo/addons/gut/LICENSE.md
================================================
The MIT License (MIT)
=====================

Copyright (c) 2018 Tom "Butch" Wesley

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


================================================
FILE: demo/addons/gut/UserFileViewer.gd
================================================
extends Window

@onready var rtl = $TextDisplay/RichTextLabel

func _get_file_as_text(path):
	var to_return = null
	var f = FileAccess.open(path, FileAccess.READ)
	if(f != null):
		to_return = f.get_as_text()
	else:
		to_return = str('ERROR:  Could not open file.  Error code ', FileAccess.get_open_error())
	return to_return

func _ready():
	rtl.clear()

func _on_OpenFile_pressed():
	$FileDialog.popup_centered()

func _on_FileDialog_file_selected(path):
	show_file(path)

func _on_Close_pressed():
	self.hide()

func show_file(path):
	var text = _get_file_as_text(path)
	if(text == ''):
		text = '<Empty File>'
	rtl.set_text(text)
	self.window_title = path

func show_open():
	self.popup_centered()
	$FileDialog.popup_centered()

func get_rich_text_label():
	return $TextDisplay/RichTextLabel

func _on_Home_pressed():
	rtl.scroll_to_line(0)

func _on_End_pressed():
	rtl.scroll_to_line(rtl.get_line_count() -1)

func _on_Copy_pressed():
	return
	# OS.clipboard = rtl.text

func _on_file_dialog_visibility_changed():
	if rtl.text.length() == 0 and not $FileDialog.visible:
		self.hide()


================================================
FILE: demo/addons/gut/UserFileViewer.gd.uid
================================================
uid://x51wilphva3d


================================================
FILE: demo/addons/gut/UserFileViewer.tscn
================================================
[gd_scene load_steps=2 format=3 uid="uid://bsm7wtt1gie4v"]

[ext_resource type="Script" uid="uid://x51wilphva3d" path="res://addons/gut/UserFileViewer.gd" id="1"]

[node name="UserFileViewer" type="Window"]
exclusive = true
script = ExtResource("1")

[node name="FileDialog" type="FileDialog" parent="."]
access = 1
show_hidden_files = true
__meta__ = {
"_edit_use_anchors_": false
}

[node name="TextDisplay" type="ColorRect" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 8.0
offset_right = -10.0
offset_bottom = -65.0
color = Color(0.2, 0.188235, 0.188235, 1)

[node name="RichTextLabel" type="RichTextLabel" parent="TextDisplay"]
anchor_right = 1.0
anchor_bottom = 1.0
focus_mode = 2
text = "In publishing and graphic design, Lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document or a typeface without relying on meaningful content. Lorem ipsum may be used before final copy is available, but it may also be used to temporarily replace copy in a process called greeking, which allows designers to consider form without the meaning of the text influencing the design.

Lorem ipsum is typically a corrupted version of De finibus bonorum et malorum, a first-century BCE text by the Roman statesman and philosopher Cicero, with words altered, added, and removed to make it nonsensical, improper Latin.

Versions of the Lorem ipsum text have been used in typesetting at least since the 1960s, when it was popularized by advertisements for Letraset transfer sheets. Lorem ipsum was introduced to the digital world in the mid-1980s when Aldus employed it in graphic and word-processing templates for its desktop publishing program PageMaker. Other popular word processors including Pages and Microsoft Word have since adopted Lorem ipsum as well."
selection_enabled = true

[node name="OpenFile" type="Button" parent="."]
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -158.0
offset_top = -50.0
offset_right = -84.0
offset_bottom = -30.0
text = "Open File"

[node name="Home" type="Button" parent="."]
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -478.0
offset_top = -50.0
offset_right = -404.0
offset_bottom = -30.0
text = "Home"

[node name="Copy" type="Button" parent="."]
anchor_top = 1.0
anchor_bottom = 1.0
offset_left = 160.0
offset_top = -50.0
offset_right = 234.0
offset_bottom = -30.0
text = "Copy"

[node name="End" type="Button" parent="."]
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -318.0
offset_top = -50.0
offset_right = -244.0
offset_bottom = -30.0
text = "End"

[node name="Close" type="Button" parent="."]
anchor_top = 1.0
anchor_bottom = 1.0
offset_left = 10.0
offset_top = -50.0
offset_right = 80.0
offset_bottom = -30.0
text = "Close"

[connection signal="file_selected" from="FileDialog" to="." method="_on_FileDialog_file_selected"]
[connection signal="visibility_changed" from="FileDialog" to="." method="_on_file_dialog_visibility_changed"]
[connection signal="pressed" from="OpenFile" to="." method="_on_OpenFile_pressed"]
[connection signal="pressed" from="Home" to="." method="_on_Home_pressed"]
[connection signal="pressed" from="Copy" to="." method="_on_Copy_pressed"]
[connection signal="pressed" from="End" to="." method="_on_End_pressed"]
[connection signal="pressed" from="Close" to="." method="_on_Close_pressed"]


================================================
FILE: demo/addons/gut/autofree.gd
================================================
# ##############################################################################
#(G)odot (U)nit (T)est class
#
# ##############################################################################
# The MIT License (MIT)
# =====================
#
# Copyright (c) 2025 Tom "Butch" Wesley
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ##############################################################################
# Class used to keep track of objects to be freed and utilities to free them.
# ##############################################################################
var _to_free = []
var _to_queue_free = []
var _ref_counted_doubles = []
var _all_instance_ids = []


func _add_instance_id(thing):
	if(thing.has_method("get_instance_id")):
		_all_instance_ids.append(thing.get_instance_id())


func add_free(thing):
	if(typeof(thing) == TYPE_OBJECT):
		_add_instance_id(thing)
		if(!thing is RefCounted):
			_to_free.append(thing)
		elif(GutUtils.is_double(thing)):
			_ref_counted_doubles.append(thing)


func add_queue_free(thing):
	if(typeof(thing) == TYPE_OBJECT):
		_add_instance_id(thing)
		_to_queue_free.append(thing)


func get_queue_free_count():
	return _to_queue_free.size()


func get_free_count():
	return _to_free.size()


func free_all():
	for node in _to_free:
		if(is_instance_valid(node)):
			if(GutUtils.is_double(node)):
				node.__gutdbl_done()
			node.free()
	_to_free.clear()

	for i in range(_to_queue_free.size()):
		if(is_instance_valid(_to_queue_free[i])):
			_to_queue_free[i].queue_free()
	_to_queue_free.clear()

	for ref_dbl in _ref_counted_doubles:
		ref_dbl.__gutdbl_done()
	_ref_counted_doubles.clear()

	_all_instance_ids.clear()


func has_instance_id(id):
	return _all_instance_ids.has(id)

================================================
FILE: demo/addons/gut/autofree.gd.uid
================================================
uid://bxjfriqxgwe0r


================================================
FILE: demo/addons/gut/awaiter.gd
================================================
extends Node

class AwaitLogger:
	var _time_waited = 0.0
	var logger = GutUtils.get_logger()
	var waiting_on = "nothing"
	var logged_initial_message = false
	var wait_log_delay := 1.0
	var disabled = false

	func waited(x):
		_time_waited += x
		if(!logged_initial_message and _time_waited >= wait_log_delay):
			log_it()
			logged_initial_message = true


	func reset():
		_time_waited = 0.0
		logged_initial_message = false


	func log_it():
		if(!disabled):
			var msg = str("--- Awaiting ", waiting_on, " ---")
			logger.wait_msg(msg)




signal timeout
signal wait_started

var await_logger = AwaitLogger.new()
var _wait_time := 0.0
var _wait_process_frames := 0
var _wait_physics_frames := 0
var _signal_to_wait_on = null

var _predicate_method = null
var _waiting_for_predicate_to_be = null

var _predicate_time_between := 0.0
var _predicate_time_between_elpased := 0.0

var _elapsed_time := 0.0
var _elapsed_frames := 0

var _did_last_wait_timeout = false
var did_last_wait_timeout = false :
	get: return _did_last_wait_timeout
	set(val): push_error("Cannot set did_last_wait_timeout")



func _ready() -> void:
	get_tree().process_frame.connect(_on_tree_process_frame)
	get_tree().physics_frame.connect(_on_tree_physics_frame)


func _on_tree_process_frame():
	# Count frames here instead of in _process so that tree order never
	# makes a difference and the count/signaling happens outside of
	# _process being called.
	if(_wait_process_frames > 0):
		_elapsed_frames += 1
		if(_elapsed_frames > _wait_process_frames):
			_end_wait()


func _on_tree_physics_frame():
	# Count frames here instead of in _physics_process so that tree order never
	# makes a difference and the count/signaling happens outside of
	# _physics_process being called.
	if(_wait_physics_frames != 0):
		_elapsed_frames += 1
		if(_elapsed_frames > _wait_physics_frames):
			_end_wait()


func _physics_process(delta):
	if(is_waiting()):
		await_logger.waited(delta)

	if(_wait_time != 0.0):
		_elapsed_time += delta
		if(_elapsed_time >= _wait_time):
			_end_wait()

	if(_predicate_method != null):
		_predicate_time_between_elpased += delta
		if(_predicate_time_between_elpased >= _predicate_time_between):
			_predicate_time_between_elpased = 0.0
			var result = _predicate_method.call()
			if(_waiting_for_predicate_to_be == false):
				if(typeof(result) != TYPE_BOOL or result != true):
					_end_wait()
			else:
				if(typeof(result) == TYPE_BOOL and result == _waiting_for_predicate_to_be):
					_end_wait()


func _end_wait():
	await_logger.reset()
	# Check for time before checking for frames so that the extra frames added
	# when waiting on a signal do not cause a false negative for timing out.
	if(_wait_time > 0):
		_did_last_wait_timeout = _elapsed_time >= _wait_time
	elif(_wait_physics_frames > 0):
		_did_last_wait_timeout = _elapsed_frames >= _wait_physics_frames
	elif(_wait_process_frames > 0):
		_did_last_wait_timeout = _elapsed_frames >= _wait_process_frames

	if(_signal_to_wait_on != null and \
	   is_instance_valid(_signal_to_wait_on.get_object()) and \
	   _signal_to_wait_on.is_connected(_signal_callback)):
		_signal_to_wait_on.disconnect(_signal_callback)

	_wait_process_frames = 0
	_wait_time = 0.0
	_wait_physics_frames = 0
	_signal_to_wait_on = null
	_predicate_method = null
	_elapsed_time = 0.0
	_elapsed_frames = 0
	timeout.emit()


const ARG_NOT_SET = '_*_argument_*_is_*_not_set_*_'
func _signal_callback(
		_arg1=ARG_NOT_SET, _arg2=ARG_NOT_SET, _arg3=ARG_NOT_SET,
		_arg4=ARG_NOT_SET, _arg5=ARG_NOT_SET, _arg6=ARG_NOT_SET,
		_arg7=ARG_NOT_SET, _arg8=ARG_NOT_SET, _arg9=ARG_NOT_SET):

	_signal_to_wait_on.disconnect(_signal_callback)
	# DO NOT _end_wait here.  For other parts of the test to get the signal that
	# was waited on, we have to wait for another frames.  For example, the
	# signal_watcher doesn't get the signal in time if we don't do this.
	_wait_process_frames = 1


func wait_seconds(x, msg=''):
	await_logger.waiting_on = str(x, " seconds ", msg)
	_did_last_wait_timeout = false
	_wait_time = x
	wait_started.emit()


func wait_process_frames(x, msg=''):
	await_logger.waiting_on = str(x, " idle frames ", msg)
	_did_last_wait_timeout = false
	_wait_process_frames = x
	wait_started.emit()


func wait_physics_frames(x, msg=''):
	await_logger.waiting_on = str(x, " physics frames ", msg)
	_did_last_wait_timeout = false
	_wait_physics_frames = x
	wait_started.emit()


func wait_for_signal(the_signal : Signal, max_time, msg=''):
	await_logger.waiting_on = str("signal ", the_signal.get_name(), " or ", max_time, "s ", msg)
	_did_last_wait_timeout = false
	the_signal.connect(_signal_callback)
	_signal_to_wait_on = the_signal
	_wait_time = max_time
	wait_started.emit()


func wait_until(predicate_function: Callable, max_time, time_between_calls:=0.0, msg=''):
	await_logger.waiting_on = str("callable to return TRUE or ", max_time, "s.  ", msg)
	_predicate_time_between = time_between_calls
	_predicate_method = predicate_function
	_wait_time = max_time

	_waiting_for_predicate_to_be = true
	_predicate_time_between_elpased = 0.0
	_did_last_wait_timeout = false

	wait_started.emit()


func wait_while(predicate_function: Callable, max_time, time_between_calls:=0.0, msg=''):
	await_logger.waiting_on = str("callable to return FALSE or ", max_time, "s.  ", msg)
	_predicate_time_between = time_between_calls
	_predicate_method = predicate_function
	_wait_time = max_time

	_waiting_for_predicate_to_be = false
	_predicate_time_between_elpased = 0.0
	_did_last_wait_timeout = false

	wait_started.emit()


func is_waiting():
	return _wait_time != 0.0 || \
		_wait_physics_frames != 0 || \
		_wait_process_frames != 0


================================================
FILE: demo/addons/gut/awaiter.gd.uid
================================================
uid://ccu4ww35edtdi


================================================
FILE: demo/addons/gut/cli/change_project_warnings.gd
================================================
extends SceneTree

var Optparse = load('res://addons/gut/cli/optparse.gd')
var WarningsManager = load("res://addons/gut/warnings_manager.gd")
const WARN_VALUE_PRINT_POSITION = 36

var godot_default_warnings = {
  "assert_always_false": 1,             "assert_always_true": 1,  			"confusable_identifier": 1,
  "confusable_local_declaration": 1,    "confusable_local_usage": 1,  		"constant_used_as_function": 1,
  "deprecated_keyword": 1,              "empty_file": 1,  					"enable": true,
  "exclude_addons": true, 				"function_used_as_property": 1,  	"get_node_default_without_onready": 2,
  "incompatible_ternary": 1,  			"inference_on_variant": 2,  		"inferred_declaration": 0,
  "int_as_enum_without_cast": 1,  		"int_as_enum_without_match": 1,  	"integer_division": 1,
  "narrowing_conversion": 1,  			"native_method_override": 2,  		"onready_with_export": 2,
  "property_used_as_function": 1,  		"redundant_await": 1,  				"redundant_static_unload": 1,
  "renamed_in_godot_4_hint": 1,  		"return_value_discarded": 0,  		"shadowed_global_identifier": 1,
  "shadowed_variable": 1,  				"shadowed_variable_base_class": 1,  "standalone_expression": 1,
  "standalone_ternary": 1,  			"static_called_on_instance": 1,  	"unassigned_variable": 1,
  "unassigned_variable_op_assign": 1,  	"unreachable_code": 1,  			"unreachable_pattern": 1,
  "unsafe_call_argument": 0,  			"unsafe_cast": 0,  					"unsafe_method_access": 0,
  "unsafe_property_access": 0,  		"unsafe_void_return": 1,  			"untyped_declaration": 0,
  "unused_local_constant": 1,  			"unused_parameter": 1,  			"unused_private_class_variable": 1,
  "unused_signal": 1,  					"unused_variable": 1
}

var gut_default_changes = {
  "exclude_addons": false, 				"redundant_await": 0,
}

var warning_settings = {}

func _setup_warning_settings():
	warning_settings["godot_default"] = godot_default_warnings
	warning_settings["current"] = WarningsManager.create_warnings_dictionary_from_project_settings()
	warning_settings["all_warn"] = WarningsManager.create_warn_all_warnings_dictionary()

	var gut_default = godot_default_warnings.duplicate()
	gut_default.merge(gut_default_changes, true)
	warning_settings["gut_default"] = gut_default


func _warn_value_to_s(value):
	var readable = str(value).capitalize()
	if(typeof(value) == TYPE_INT):
		readable = WarningsManager.WARNING_LOOKUP.get(value, str(readable, ' ???'))
		readable = readable.capitalize()
	return readable


func _human_readable(warnings):
	var to_return = ""
	for key in warnings:
		var readable = _warn_value_to_s(warnings[key])
		to_return += str(key.capitalize().rpad(35, ' '), readable, "\n")
	return to_return


func _dump_settings(which):
	if(warning_settings.has(which)):
		GutUtils.pretty_print(warning_settings[which])
	else:
		print("UNKNOWN print option ", which)


func _print_settings(which):
	if(warning_settings.has(which)):
		print(_human_readable(warning_settings[which]))
	else:
		print("UNKNOWN print option ", which)


func _apply_settings(which):
	if(!warning_settings.has(which)):
		print("UNKNOWN set option ", which)
		return

	var pre_settings = warning_settings["current"]
	var new_settings = warning_settings[which]

	if(new_settings == pre_settings):
		print("-- Settings are the same, no changes were made --")
		return

	WarningsManager.apply_warnings_dictionary(new_settings)
	ProjectSettings.save()
	print("-- Project Warning Settings have been updated --")
	print(_diff_changes_text(pre_settings))


func _diff_text(w1, w2, diff_col_pad=10):
	var to_return = ""
	for key in w1:
		var v1_text = _warn_value_to_s(w1[key])
		var v2_text = _warn_value_to_s(w2[key])
		var diff_text = v1_text
		var prefix = "  "

		if(v1_text != v2_text):
			var diff_prefix = " "
			if(w1[key] > w2[key]):
				diff_prefix = "-"
			else:
				diff_prefix = "+"
			prefix = "* "
			diff_text = str(v1_text.rpad(diff_col_pad, ' '), diff_prefix, v2_text)

		to_return += str(str(prefix, key.capitalize()).rpad(WARN_VALUE_PRINT_POSITION, ' '), diff_text, "\n")

	return to_return.rstrip("\n")


func _diff_changes_text(pre_settings):
	var orig_diff_text = _diff_text(
		pre_settings,
		WarningsManager.create_warnings_dictionary_from_project_settings(),
		0)
	# these next two lines are fragile and brute force...enjoy
	var diff_text = orig_diff_text.replace("-", " -> ")
	diff_text = diff_text.replace("+", " -> ")

	if(orig_diff_text == diff_text):
		diff_text += "\n-- No changes were made --"
	else:
		diff_text += "\nChanges will not be visible in Godot until it is restarted.\n"
		diff_text += "Even if it asks you to reload...Maybe.  Probably."

	return diff_text



func _diff(name_1, name_2):
	if(warning_settings.has(name_1) and warning_settings.has(name_2)):
		var c2_pad = name_1.length() + 2
		var heading = str(" ".repeat(WARN_VALUE_PRINT_POSITION), name_1.rpad(c2_pad, ' '), name_2, "\n")
		heading += str(
			" ".repeat(WARN_VALUE_PRINT_POSITION),
			"-".repeat(name_1.length()).rpad(c2_pad, " "),
			"-".repeat(name_2.length()),
			"\n")

		var text = _diff_text(warning_settings[name_1], warning_settings[name_2], c2_pad)

		print(heading)
		print(text)

		var diff_count = 0
		for line in text.split("\n"):
			if(!line.begins_with("  ")):
				diff_count += 1

		if(diff_count == 0):
			print('-- [', name_1, "] and [", name_2, "] are the same --")
		else:
			print('-- There are ', diff_count, ' differences between [', name_1, "] and [", name_2, "] --")
	else:
		print("One or more unknown Warning Level Names:, [", name_1, "] [", name_2, "]")


func _set_settings(nvps):
	var pre_settings = warning_settings["current"]
	for i in range(nvps.size()/2):
		var s_name = nvps[i * 2]
		var s_value = nvps[i * 2 + 1]
		if(godot_default_warnings.has(s_name)):
			var t = typeof(godot_default_warnings[s_name])
			if(t == TYPE_INT):
				s_value = s_value.to_int()
			elif(t == TYPE_BOOL):
				s_value = s_value.to_lower() == 'true'

			WarningsManager.set_project_setting_warning(s_name, s_value)
			ProjectSettings.save()
	print(_diff_changes_text(pre_settings))



func _setup_options():
	var opts = Optparse.new()
	opts.banner = """
	This script prints info about or sets the warning settings for the project.
	Each action requires one or more Warning Level Names.

	Warning Level Names:
	    * current        The current settings for the project.
	    * godot_default  The default settings for Godot.
	    * gut_default    The warning settings that is used when developing GUT.
	    * all_warn       Everything set to warn.
	""".dedent()

	opts.add('-h', false, 'Print this help')
	opts.add('-set', [], "Sets a single setting in the project settings and saves.\n" +
						 "Use -dump to see a list of setting names and values.\n" +
						 "Example: -set enabled,true -set unsafe_cast,2 -set unreachable_code,0")
	opts.add_heading(" Actions (require Warning Level Name)")
	opts.add('-diff', [], "Shows the difference between two Warning Level Names.\n" +
						  "Example:  -diff current,all_warn")
	opts.add('-dump', 'none', "Prints a dictionary of the warning values.")
	opts.add('-print', 'none', "Print human readable warning values.")
	opts.add('-apply', 'none', "Applys one of the Warning Level Names to the project settings.  You should restart after using this")

	return opts

func _print_help(opts):
	opts.print_help()



func _init():
	# Testing might set this flag but it should never be disabled for this tool
	# or it cannot save project settings, but says it did.  Sneakily use the
	# private property to get around this property being read-only.  Don't
	# try this at home.
	WarningsManager._disabled = false

	_setup_warning_settings()

	var opts = _setup_options()
	opts.parse()

	if(opts.unused.size() != 0):
		opts.print_help()
		print("Unknown arguments ", opts.unused)
	if(opts.values.h):
		opts.print_help()
	elif(opts.values.print != 'none'):
		_print_settings(opts.values.print)
	elif(opts.values.dump != 'none'):
		_dump_settings(opts.values.dump)
	elif(opts.values.apply != 'none'):
		_apply_settings(opts.values.apply )
	elif(opts.values.diff.size() == 2):
		_diff(opts.values.diff[0], opts.values.diff[1])
	elif(opts.values.set.size() % 2 == 0):
		_set_settings(opts.values.set)
	else:
		opts.print_help()
		print("You didn't specify any options or too many or not the right size or something invalid.  I don't know what you want to do.")

	quit()

================================================
FILE: demo/addons/gut/cli/change_project_warnings.gd.uid
================================================
uid://1pauyfnd1cre


================================================
FILE: demo/addons/gut/cli/gut_cli.gd
================================================
extends Node

var Optparse = load('res://addons/gut/cli/optparse.gd')
var Gut = load('res://addons/gut/gut.gd')
var GutRunner = load('res://addons/gut/gui/GutRunner.tscn')

# ------------------------------------------------------------------------------
# Helper class to resolve the various different places where an option can
# be set.  Using the get_value method will enforce the order of precedence of:
# 	1.  command line value
#	2.  config file value
#	3.  default value
#
# The idea is that you set the base_opts.  That will get you a copies of the
# hash with null values for the other types of values.  Lower precedented hashes
# will punch through null values of higher precedented hashes.
# ------------------------------------------------------------------------------
class OptionResolver:
	var base_opts = {}
	var cmd_opts = {}
	var config_opts = {}


	func get_value(key):
		return _nvl(cmd_opts[key], _nvl(config_opts[key], base_opts[key]))

	func set_base_opts(opts):
		base_opts = opts
		cmd_opts = _null_copy(opts)
		config_opts = _null_copy(opts)

	# creates a copy of a hash with all values null.
	func _null_copy(h):
		var new_hash = {}
		for key in h:
			new_hash[key] = null
		return new_hash

	func _nvl(a, b):
		if(a == null):
			return b
		else:
			return a

	func _string_it(h):
		var to_return = ''
		for key in h:
			to_return += str('(',key, ':', _nvl(h[key], 'NULL'), ')')
		return to_return

	func to_s():
		return str("base:\n", _string_it(base_opts), "\n", \
				"config:\n", _string_it(config_opts), "\n", \
				"cmd:\n", _string_it(cmd_opts), "\n", \
				"resolved:\n", _string_it(get_resolved_values()))

	func get_resolved_values():
		var to_return = {}
		for key in base_opts:
			to_return[key] = get_value(key)
		return to_return

	func to_s_verbose():
		var to_return = ''
		var resolved = get_resolved_values()
		for key in base_opts:
			to_return += str(key, "\n")
			to_return += str('  default: ', _nvl(base_opts[key], 'NULL'), "\n")
			to_return += str('  config:  ', _nvl(config_opts[key], ' --'), "\n")
			to_return += str('  cmd:     ', _nvl(cmd_opts[key], ' --'), "\n")
			to_return += str('  final:   ', _nvl(resolved[key], 'NULL'), "\n")

		return to_return

# ------------------------------------------------------------------------------
# Here starts the actual script that uses the Options class to kick off Gut
# and run your tests.
# ------------------------------------------------------------------------------
var _gut_config = load('res://addons/gut/gut_config.gd').new()

# array of command line options specified
var _final_opts = []


func setup_options(options, font_names):
	var opts = Optparse.new()
	opts.banner =\
"""
The GUT CLI
-----------
The default behavior for GUT is to load options from a res://.gutconfig.json if
it exists.  Any options specified on the command line will take precedence over
options specified in the gutconfig file.  You can specify a different gutconfig
file with the -gconfig option.

To generate a .gutconfig.json file you can use -gprint_gutconfig_sample
To see the effective values of a CLI command and a gutconfig use -gpo

Values for options can be supplied using:
    option=value    # no space around "="
    option value    # a space between option and value w/o =

Options whose values are lists/arrays can be specified multiple times:
	-gdir=a,b
	-gdir c,d
	-gdir e
	# results in -gdir equaling [a, b, c, d, e]

To not use an empty value instead of a default value, specifiy the option with
an immediate "=":
	-gconfig=
"""
	opts.add_heading("Test Config:")
	opts.add('-gdir', options.dirs, 'List of directories to search for test scripts in.')
	opts.add('-ginclude_subdirs', false, 'Flag to include all subdirectories specified with -gdir.')
	opts.add('-gtest', [], 'List of full paths to test scripts to run.')
	opts.add('-gprefix', options.prefix, 'Prefix used to find tests when specifying -gdir.  Default "[default]".')
	opts.add('-gsuffix', options.suffix, 'Test script suffix, including .gd extension.  Default "[default]".')
	opts.add('-gconfig', 'res://.gutconfig.json', 'The config file to load options from.  The default is [default].  Use "-gconfig=" to not use a config file.')
	opts.add('-gpre_run_script', '', 'pre-run hook script path')
	opts.add('-gpost_run_script', '', 'post-run hook script path')
	opts.add('-gerrors_do_not_cause_failure', false, 'When an internal GUT error occurs tests will fail.  With this option set, that does not happen.')
	opts.add('-gdouble_strategy', 'SCRIPT_ONLY', 'Default strategy to use when doubling.  Valid values are [INCLUDE_NATIVE, SCRIPT_ONLY].  Default "[default]"')

	opts.add_heading("Run Options:")
	opts.add('-gselect', '', 'All scripts that contain the specified string in their filename will be ran')
	opts.add('-ginner_class', '', 'Only run inner classes that contain the specified string in their name.')
	opts.add('-gunit_test_name', '', 'Any test that contains the specified text will be run, all others will be skipped.')
	opts.add('-gexit', false, 'Exit after running tests.  If not specified you have to manually close the window.')
	opts.add('-gexit_on_success', false, 'Only exit if zero tests fail.')
	opts.add('-gignore_pause', false, 'Ignores any calls to pause_before_teardown.')
	opts.add('-gno_error_tracking', false, 'Disable error tracking.')
	opts.add('-gfailure_error_types', options.failure_error_types, 'Error types that will cause tests to fail if the are encountered during the execution of a test.  Default "[default]"')

	opts.add_heading("Display Settings:")
	opts.add('-glog', options.log_level, 'Log level [0-3].  Default [default]')
	opts.add('-ghide_orphans', false, 'Display orphan counts for tests and scripts.  Default [default].')
	opts.add('-gmaximize', false, 'Maximizes test runner window to fit the viewport.')
	opts.add('-gcompact_mode', false, 'The runner will be in compact mode.  This overrides -gmaximize.')
	opts.add('-gopacity', options.opacity, 'Set opacity of test runner window. Use range 0 - 100. 0 = transparent, 100 = opaque.')
	opts.add('-gdisable_colors', false, 'Disable command line colors.')
	opts.add('-gfont_name', options.font_name, str('Valid values are:  ', font_names, '.  Default "[default]"'))
	opts.add('-gfont_size', options.font_size, 'Font size, default "[default]"')
	opts.add('-gbackground_color', options.background_color, 'Background color as an html color, default "[default]"')
	opts.add('-gfont_color',options.font_color, 'Font color as an html color, default "[default]"')
	opts.add('-gpaint_after', options.paint_after, 'Delay before GUT will add a 1 frame pause to paint the screen/GUI.  default [default]')
	opts.add('-gwait_log_delay', options.wait_log_delay, 'Delay before GUT will print a message to indicate a test is awaiting one of the wait_* methods.  Default [default]')

	opts.add_heading("Result Export:")
	opts.add('-gjunit_xml_file', options.junit_xml_file, 'Export results of run to this file in the Junit XML format.')
	opts.add('-gjunit_xml_timestamp', options.junit_xml_timestamp, 'Include a timestamp in the -gjunit_xml_file, default [default]')

	opts.add_heading("Help:")
	opts.add('-gh', false, 'Print this help.  You did this to see this, so you probably understand.')
	opts.add('-gpo', false, 'Print option values from all sources and the value used.')
	opts.add('-gprint_gutconfig_sample', false, 'Print out json that can be used to make a gutconfig file.')

	# run as in editor, for shelling out purposes through Editor.
	var o = opts.add('-graie', false, 'do not use')
	o.show_in_help = false
	return opts


# Parses options, applying them to the _tester or setting values
# in the options struct.
func extract_command_line_options(from, to):
	to.compact_mode = from.get_value_or_null('-gcompact_mode')
	to.config_file = from.get_value_or_null('-gconfig')
	to.dirs = from.get_value_or_null('-gdir')
	to.disable_colors =  from.get_value_or_null('-gdisable_colors')
	to.double_strategy = from.get_value_or_null('-gdouble_strategy')
	to.errors_do_not_cause_failure = from.get_value_or_null('-gerrors_do_not_cause_failure')
	to.hide_orphans = from.get_value_or_null('-ghide_orphans')
	to.ignore_pause = from.get_value_or_null('-gignore_pause')
	to.include_subdirs = from.get_value_or_null('-ginclude_subdirs')
	to.inner_class = from.get_value_or_null('-ginner_class')
	to.log_level = from.get_value_or_null('-glog')
	to.opacity = from.get_value_or_null('-gopacity')
	to.post_run_script = from.get_value_or_null('-gpost_run_script')
	to.pre_run_script = from.get_value_or_null('-gpre_run_script')
	to.prefix = from.get_value_or_null('-gprefix')
	to.selected = from.get_value_or_null('-gselect')
	to.should_exit = from.get_value_or_null('-gexit')
	to.should_exit_on_success = from.get_value_or_null('-gexit_on_success')
	to.should_maximize = from.get_value_or_null('-gmaximize')
	to.suffix = from.get_value_or_null('-gsuffix')
	to.tests = from.get_value_or_null('-gtest')
	to.unit_test_name = from.get_value_or_null('-gunit_test_name')
	to.wait_log_delay = from.get_value_or_null('-gwait_log_delay')

	to.background_color = from.get_value_or_null('-gbackground_color')
	to.font_color = from.get_value_or_null('-gfont_color')
	to.font_name = from.get_value_or_null('-gfont_name')
	to.font_size = from.get_value_or_null('-gfont_size')
	to.paint_after = from.get_value_or_null('-gpaint_after')

	to.junit_xml_file = from.get_value_or_null('-gjunit_xml_file')
	to.junit_xml_timestamp = from.get_value_or_null('-gjunit_xml_timestamp')

	to.failure_error_types = from.get_value_or_null('-gfailure_error_types')
	to.no_error_tracking = from.get_value_or_null('-gno_error_tracking')
	to.raie = from.get_value_or_null('-graie')



func _print_gutconfigs(values):
	var header = """Here is a sample of a full .gutconfig.json file.
You do not need to specify all values in your own file.  The values supplied in
this sample are what would be used if you ran gut w/o the -gprint_gutconfig_sample
option.   Option priority is:  command-line, .gutconfig, default)."""
	print("\n", header.replace("\n", ' '), "\n")
	var resolved = values

	# remove_at some options that don't make sense to be in config
	resolved.erase("config_file")
	resolved.erase("show_help")

	print(JSON.stringify(resolved, '  '))

	for key in resolved:
		resolved[key] = null

	print("\n\nAnd here's an empty config for you fill in what you want.")
	print(JSON.stringify(resolved, ' '))


func _run_tests(opt_resolver):
	_final_opts = opt_resolver.get_resolved_values();
	_gut_config.options = _final_opts

	var runner = GutRunner.instantiate()
	runner.set_gut_config(_gut_config)
	get_tree().root.add_child(runner)

	if(opt_resolver.cmd_opts.raie):
		runner.run_from_editor()
	else:
		runner.run_tests()


# parse options and run Gut
func main():
	var opt_resolver = OptionResolver.new()
	opt_resolver.set_base_opts(_gut_config.default_options)

	var cli_opts = setup_options(_gut_config.default_options, _gut_config.valid_fonts)

	cli_opts.parse()
	var all_options_valid = cli_opts.unused.size() == 0
	extract_command_line_options(cli_opts, opt_resolver.cmd_opts)

	var config_path = opt_resolver.get_value('config_file')
	var load_result = 1
	# Checking for an empty config path allows us to not use a config file via
	# the -gconfig_file option since using "-gconfig_file=" or -gconfig_file=''"
	# will result in an empty string.
	if(config_path != ''):
		load_result = _gut_config.load_options_no_defaults(config_path)

	# SHORTCIRCUIT
	if(!all_options_valid):
		print('Unknown arguments:  ', cli_opts.unused)
		get_tree().quit(1)
	elif(load_result == -1):
		print('Invalid gutconfig ', load_result)
		get_tree().quit(1)
	else:
		opt_resolver.config_opts = _gut_config.options

		if(cli_opts.get_value('-gh')):
			print(GutUtils.version_numbers.get_version_text())
			cli_opts.print_help()
			get_tree().quit(0)
		elif(cli_opts.get_value('-gpo')):
			print('All config options and where they are specified.  ' +
				'The "final" value shows which value will actually be used ' +
				'based on order of precedence (default < .gutconfig < cmd line).' + "\n")
			print(opt_resolver.to_s_verbose())
			get_tree().quit(0)
		elif(cli_opts.get_value('-gprint_gutconfig_sample')):
			_print_gutconfigs(opt_resolver.get_resolved_values())
			get_tree().quit(0)
		else:
			_run_tests(opt_resolver)



# ##############################################################################
#(G)odot (U)nit (T)est class
#
# ##############################################################################
# The MIT License (MIT)
# =====================
#
# Copyright (c) 2025 Tom "Butch" Wesley
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ##############################################################################


================================================
FILE: demo/addons/gut/cli/gut_cli.gd.uid
================================================
uid://bhuudqinp4bth


================================================
FILE: demo/addons/gut/cli/optparse.gd
================================================
## Parses command line arguments, as one might expect.
##
## Parses command line arguments with a bunch of options including generating
## text that displays all the arguments your script accepts.  This
## is included in the GUT ClassRef since it might be usable by others and is
## portable (everything it needs is in this one file).
## [br]
## This does alot, if you want to see it in action have a look at
##	[url=https://github.com/bitwes/Gut/blob/main/scratch/optparse_example.gd]scratch/optparse_example.gd[/url]
## [codeblock lang=text]
##
## Godot Argument Lists
## -------------------------
## There are two sets of command line arguments that Godot populates:
##	OS.get_cmdline_args
##	OS.get_cmdline_user_args.
##
## OS.get_cmdline_args contains any arguments that are not used by the engine
## itself.  This means options like --help and -d will never appear in this list
## since these are used by the engine.  The one exception is the -s option which
## is always included as the first entry and the script path as the second.
## Optparse ignores these values for argument processing but can be accessed
## with my_optparse.options.script_option.  This list does not contain any
## arguments that appear in OS.get_cmdline_user_args.
##
## OS.get_cmdline_user_args contains any arguments that appear on the command
## line AFTER " -- " or " ++ ".  This list CAN contain options that the engine
## would otherwise use, and are ignored completely by the engine.
##
## The parse method, by default, includes arguments from OS.get_cmdline_args and
## OS.get_cmdline_user_args.  You can optionally pass one of these to the parse
## method to limit which arguments are parsed.  You can also conjure up your own
## array of arguments and pass that to parse.
##
## See Godot's documentation for get_cmdline_args and get_cmdline_user_args for
## more information.
##
##
## Adding Options
## --------------
## Use the following to add options to be parsed.  These methods return the
## created Option instance.  See that class above for more info.  You can use
## the returned instance to get values, or use get_value/get_value_or_null.
##   add("--name", "default", "Description goes here")
##   add(["--name", "--aliases"], "default", "Description goes here")
##   add_required(["--name", "--aliases"], "default", "Description goes here")
##   add_positional("--name", "default", "Description goes here")
##   add_positional_required("--name", "default", "Description goes here")
##
## get_value will return the value of the option or the default if it was not
## set.  get_value_or_null will return the value of the option or null if it was
## not set.
##
## The Datatype for an option is determined from the default value supplied to
## the various add methods.  Supported types are
##   String
##   Int
##   Float
##   Array of strings
##   Boolean
##
##
## Value Parsing
## -------------
## optparse uses option_name_prefix to differentiate between option names and
## values.  Any argument that starts with this value will be treated as an
## argument name.  The default is "-".  Set this before calling parse if you want
## to change it.
##
## Values for options can be supplied on the command line with or without an "=":
##	option=value    # no space around "="
##	option value    # a space between option and value w/o =
## There is no way to escape "=" at this time.
##
## Array options can be specified multiple times and/or set from a comma delimited
## list.
##   -gdir=a,b
##   -gdir c,d
##   -gdir e
## Results in -gdir equaling [a, b, c, d, e].  There is no way to escape commas
## at this time.
##
## To specify an empty list via the command line follow the option with an equal
## sign
##   -gdir=
##
## Boolean options will have thier value set to !default when they are supplied
## on the command line.  Boolean options cannot have a value on the command line.
## They are either supplied or not.
##
## If a value is not an array and is specified multiple times on the command line
## then the last entry will be used as the value.
##
## Positional argument values are parsed after all named arguments are parsed.
## This means that other options can appear before, between, and after positional
## arguments.
##   --foo=bar positional_0_value --disabled --bar foo positional_1_value --a_flag
##
## Anything that is not used by named or positional arguments will appear in the
## unused property.  You can use this to detect unrecognized arguments or treat
## everything else provided as a list of things, or whatever you want.  You can
## use is_option on the elements of unused (or whatever you want really) to see
## if optparse would treat it as an option name.
##
## Use get_missing_required_options to get an array of Option with all required
## options that were not found when parsing.
##
## The parsed_args property holds the list of arguments that were parsed.
##
##
## Help Generation
## ---------------
## You can call get_help to generate help text, or you can just call print_help
## and this will print it for you.
##
## Set the banner property to any text you want to appear before the usage and
## options sections.
##
## Options are printed in the order they are added.  You can add a heading for
## different options sections with add_heading.
##   add("--asdf", 1, "This will have no heading")
##   add_heading("foo")
##   add("--foo", false, "This will have the foo heading")
##   add("--another_foo", 1.5, "This too.")
##   add_heading("This is after foo")
##   add("--bar", true, "You probably get it by now.")
##
## If you include "[default]" in the description of a option, then the help will
## substitue it with the default value.
## [/codeblock]


#-------------------------------------------------------------------------------
# Holds all the properties of a command line option
#
# value will return the default when it has not been set.
#-------------------------------------------------------------------------------
class Option:
	var _has_been_set = false
	var _value = null
	# REMEMBER that when this option is an array, you have to set the value
	# before you alter the contents of the array (append etc) or has_been_set
	# will return false and it might not be used right.  For example
	# get_value_or_null will return null when you've actually changed the value.
	var value = _value:
		get:
			return _value

		set(val):
			_has_been_set = true
			_value = val

	var option_name = ''
	var default = null
	var description = ''
	var required = false
	var aliases: Array[String] = []
	var show_in_help = true


	func _init(name,default_value,desc=''):
		option_name = name
		default = default_value
		description = desc
		_value = default


	func wrap_text(text, left_indent, max_length, wiggle_room=15):
		var line_indent = str("\n", " ".repeat(left_indent + 1))
		var wrapped = ''
		var position = 0
		var split_length = max_length
		while(position < text.length()):
			if(position > 0):
				wrapped += line_indent

			var split_by = split_length
			if(position + split_by + wiggle_room >= text.length()):
				split_by = text.length() - position
			else:
				var min_space = text.rfind(' ', position + split_length)
				var max_space = text.find(' ', position + split_length)
				if(max_space <= position + split_length + wiggle_room):
					split_by = max_space - position
				else:
					split_by = min_space - position

			wrapped += text.substr(position, split_by).lstrip(' ')

			if(position == 0):
				split_length = max_length - left_indent

	
Download .txt
gitextract_oki6utj3/

├── .clang-format
├── .gitattributes
├── .github/
│   ├── actions/
│   │   ├── create-android-plugin/
│   │   │   └── action.yaml
│   │   └── create-native-build/
│   │       └── action.yaml
│   └── workflows/
│       ├── check_pr.yml
│       └── release.yml
├── .gitignore
├── .gitmodules
├── .readthedocs.yml
├── Android.mk
├── LICENSE
├── README.md
├── SConstruct
├── android-plugin/
│   ├── .gitignore
│   ├── build.gradle.kts
│   ├── gradle/
│   │   └── wrapper/
│   │       ├── gradle-wrapper.jar
│   │       └── gradle-wrapper.properties
│   ├── gradle.properties
│   ├── gradlew
│   ├── gradlew.bat
│   ├── library/
│   │   ├── .gitignore
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       └── main/
│   │           ├── AndroidManifest.xml
│   │           ├── kotlin/
│   │           │   └── com/
│   │           │       └── utopiarise/
│   │           │           └── godot/
│   │           │               └── fmod/
│   │           │                   └── android/
│   │           │                       └── plugin/
│   │           │                           └── FmodPlugin.kt
│   │           └── resources/
│   │               └── fmod-android-license.txt
│   └── settings.gradle.kts
├── demo/
│   ├── .gitattributes
│   ├── .gitignore
│   ├── .gutconfig.json
│   ├── addons/
│   │   ├── fmod/
│   │   │   ├── .gitignore
│   │   │   ├── FmodAndroidExportPlugin.gd
│   │   │   ├── FmodAndroidExportPlugin.gd.uid
│   │   │   ├── FmodManager.gd
│   │   │   ├── FmodManager.gd.uid
│   │   │   ├── FmodPlugin.gd
│   │   │   ├── FmodPlugin.gd.uid
│   │   │   ├── fmod.gdextension
│   │   │   ├── fmod.gdextension.uid
│   │   │   ├── icons/
│   │   │   │   ├── bank_icon.svg.import
│   │   │   │   ├── bus_icon.svg.import
│   │   │   │   ├── c_parameter_icon.svg.import
│   │   │   │   ├── d_parameter_icon.svg.import
│   │   │   │   ├── event_icon.svg.import
│   │   │   │   ├── fmod_emitter.png.import
│   │   │   │   ├── fmod_icon.svg.import
│   │   │   │   ├── snapshot_icon.svg.import
│   │   │   │   └── vca_icon.svg.import
│   │   │   ├── libs/
│   │   │   │   ├── android/
│   │   │   │   │   └── arm64/
│   │   │   │   │       └── CopyPast_Fmod_Libs_Here.txt
│   │   │   │   ├── iOS/
│   │   │   │   │   └── CopyPast_Fmod_Libs_Here.txt
│   │   │   │   ├── linux/
│   │   │   │   │   └── CopyPast_Fmod_Libs_Here.txt
│   │   │   │   ├── macos/
│   │   │   │   │   ├── CopyPast_Fmod_Libs_Here.txt
│   │   │   │   │   ├── libGodotFmod.macos.editor.framework/
│   │   │   │   │   │   └── Info.plist
│   │   │   │   │   ├── libGodotFmod.macos.template_debug.framework/
│   │   │   │   │   │   └── Info.plist
│   │   │   │   │   └── libGodotFmod.macos.template_release.framework/
│   │   │   │   │       └── Info.plist
│   │   │   │   └── windows/
│   │   │   │       └── CopyPast_Fmod_Libs_Here.txt
│   │   │   ├── plugin.cfg
│   │   │   └── tool/
│   │   │       ├── FmodBankDatabase.gd
│   │   │       ├── FmodBankDatabase.gd.uid
│   │   │       ├── inspectors/
│   │   │       │   ├── FmodBankLoaderPropertyInspectorPlugin.gd
│   │   │       │   ├── FmodBankLoaderPropertyInspectorPlugin.gd.uid
│   │   │       │   ├── FmodEmitterPropertyInspectorPlugin.gd
│   │   │       │   └── FmodEmitterPropertyInspectorPlugin.gd.uid
│   │   │       ├── performances/
│   │   │       │   ├── PerformancesDisplay.gd
│   │   │       │   └── PerformancesDisplay.gd.uid
│   │   │       ├── property_editors/
│   │   │       │   ├── FmodBankPathEditorProperty.gd
│   │   │       │   ├── FmodBankPathEditorProperty.gd.uid
│   │   │       │   ├── FmodBankPathsPropertyEditorUi.tscn
│   │   │       │   ├── FmodEventEditorProperty.gd
│   │   │       │   ├── FmodEventEditorProperty.gd.uid
│   │   │       │   ├── FmodEventEditorProperty.tscn
│   │   │       │   ├── FmodGuidAndPathPropertyEditorUi.gd
│   │   │       │   ├── FmodGuidAndPathPropertyEditorUi.gd.uid
│   │   │       │   ├── FmodGuidAndPathPropertyEditorUi.tscn
│   │   │       │   ├── FmodPathEditorProperty.gd
│   │   │       │   ├── FmodPathEditorProperty.gd.uid
│   │   │       │   └── FmodPathEditorProperty.tscn
│   │   │       └── ui/
│   │   │           ├── EventParametersDisplay.gd
│   │   │           ├── EventParametersDisplay.gd.uid
│   │   │           ├── EventParametersDisplay.tscn
│   │   │           ├── EventParametersWindow.tscn
│   │   │           ├── EventPlayControls.gd
│   │   │           ├── EventPlayControls.gd.uid
│   │   │           ├── FmodBankExplorer.gd
│   │   │           ├── FmodBankExplorer.gd.uid
│   │   │           ├── FmodBankExplorer.tscn
│   │   │           ├── ParameterDisplay.gd
│   │   │           ├── ParameterDisplay.gd.uid
│   │   │           ├── ParameterDisplay.tscn
│   │   │           └── TestFmodBankExplorer.tscn
│   │   └── gut/
│   │       ├── GutScene.gd
│   │       ├── GutScene.gd.uid
│   │       ├── GutScene.tscn
│   │       ├── LICENSE.md
│   │       ├── UserFileViewer.gd
│   │       ├── UserFileViewer.gd.uid
│   │       ├── UserFileViewer.tscn
│   │       ├── autofree.gd
│   │       ├── autofree.gd.uid
│   │       ├── awaiter.gd
│   │       ├── awaiter.gd.uid
│   │       ├── cli/
│   │       │   ├── change_project_warnings.gd
│   │       │   ├── change_project_warnings.gd.uid
│   │       │   ├── gut_cli.gd
│   │       │   ├── gut_cli.gd.uid
│   │       │   ├── optparse.gd
│   │       │   └── optparse.gd.uid
│   │       ├── collected_script.gd
│   │       ├── collected_script.gd.uid
│   │       ├── collected_test.gd
│   │       ├── collected_test.gd.uid
│   │       ├── comparator.gd
│   │       ├── comparator.gd.uid
│   │       ├── compare_result.gd
│   │       ├── compare_result.gd.uid
│   │       ├── diff_formatter.gd
│   │       ├── diff_formatter.gd.uid
│   │       ├── diff_tool.gd
│   │       ├── diff_tool.gd.uid
│   │       ├── double_templates/
│   │       │   ├── function_template.txt
│   │       │   ├── init_template.txt
│   │       │   └── script_template.txt
│   │       ├── double_tools.gd
│   │       ├── double_tools.gd.uid
│   │       ├── doubler.gd
│   │       ├── doubler.gd.uid
│   │       ├── dynamic_gdscript.gd
│   │       ├── dynamic_gdscript.gd.uid
│   │       ├── editor_caret_context_notifier.gd
│   │       ├── editor_caret_context_notifier.gd.uid
│   │       ├── error_tracker.gd
│   │       ├── error_tracker.gd.uid
│   │       ├── fonts/
│   │       │   └── OFL.txt
│   │       ├── gui/
│   │       │   ├── EditorRadioButton.tres
│   │       │   ├── GutBottomPanel.gd
│   │       │   ├── GutBottomPanel.gd.uid
│   │       │   ├── GutBottomPanel.tscn
│   │       │   ├── GutControl.gd
│   │       │   ├── GutControl.gd.uid
│   │       │   ├── GutControl.tscn
│   │       │   ├── GutEditorWindow.gd
│   │       │   ├── GutEditorWindow.gd.uid
│   │       │   ├── GutEditorWindow.tscn
│   │       │   ├── GutLogo.tscn
│   │       │   ├── GutRunner.gd
│   │       │   ├── GutRunner.gd.uid
│   │       │   ├── GutRunner.tscn
│   │       │   ├── GutSceneTheme.tres
│   │       │   ├── MinGui.tscn
│   │       │   ├── NormalGui.tscn
│   │       │   ├── OutputText.gd
│   │       │   ├── OutputText.gd.uid
│   │       │   ├── OutputText.tscn
│   │       │   ├── ResizeHandle.gd
│   │       │   ├── ResizeHandle.gd.uid
│   │       │   ├── ResizeHandle.tscn
│   │       │   ├── ResultsTree.gd
│   │       │   ├── ResultsTree.gd.uid
│   │       │   ├── ResultsTree.tscn
│   │       │   ├── RunAtCursor.gd
│   │       │   ├── RunAtCursor.gd.uid
│   │       │   ├── RunAtCursor.tscn
│   │       │   ├── RunExternally.gd
│   │       │   ├── RunExternally.gd.uid
│   │       │   ├── RunExternally.tscn
│   │       │   ├── RunResults.gd
│   │       │   ├── RunResults.gd.uid
│   │       │   ├── RunResults.tscn
│   │       │   ├── Settings.tscn
│   │       │   ├── ShellOutOptions.gd
│   │       │   ├── ShellOutOptions.gd.uid
│   │       │   ├── ShellOutOptions.tscn
│   │       │   ├── ShortcutButton.gd
│   │       │   ├── ShortcutButton.gd.uid
│   │       │   ├── ShortcutButton.tscn
│   │       │   ├── ShortcutDialog.gd
│   │       │   ├── ShortcutDialog.gd.uid
│   │       │   ├── ShortcutDialog.tscn
│   │       │   ├── about.gd
│   │       │   ├── about.gd.uid
│   │       │   ├── about.tscn
│   │       │   ├── editor_globals.gd
│   │       │   ├── editor_globals.gd.uid
│   │       │   ├── gut_config_gui.gd
│   │       │   ├── gut_config_gui.gd.uid
│   │       │   ├── gut_gui.gd
│   │       │   ├── gut_gui.gd.uid
│   │       │   ├── gut_logo.gd
│   │       │   ├── gut_logo.gd.uid
│   │       │   ├── gut_user_preferences.gd
│   │       │   ├── gut_user_preferences.gd.uid
│   │       │   ├── option_maker.gd
│   │       │   ├── option_maker.gd.uid
│   │       │   ├── panel_controls.gd
│   │       │   ├── panel_controls.gd.uid
│   │       │   ├── run_from_editor.gd
│   │       │   ├── run_from_editor.gd.uid
│   │       │   └── run_from_editor.tscn
│   │       ├── gut.gd
│   │       ├── gut.gd.uid
│   │       ├── gut_cmdln.gd
│   │       ├── gut_cmdln.gd.uid
│   │       ├── gut_config.gd
│   │       ├── gut_config.gd.uid
│   │       ├── gut_fonts.gd
│   │       ├── gut_fonts.gd.uid
│   │       ├── gut_loader.gd
│   │       ├── gut_loader.gd.uid
│   │       ├── gut_loader_the_scene.tscn
│   │       ├── gut_menu.gd
│   │       ├── gut_menu.gd.uid
│   │       ├── gut_plugin.gd
│   │       ├── gut_plugin.gd.uid
│   │       ├── gut_to_move.gd
│   │       ├── gut_to_move.gd.uid
│   │       ├── gut_tracked_error.gd
│   │       ├── gut_tracked_error.gd.uid
│   │       ├── gut_vscode_debugger.gd
│   │       ├── gut_vscode_debugger.gd.uid
│   │       ├── hook_script.gd
│   │       ├── hook_script.gd.uid
│   │       ├── inner_class_registry.gd
│   │       ├── inner_class_registry.gd.uid
│   │       ├── input_factory.gd
│   │       ├── input_factory.gd.uid
│   │       ├── input_sender.gd
│   │       ├── input_sender.gd.uid
│   │       ├── junit_xml_export.gd
│   │       ├── junit_xml_export.gd.uid
│   │       ├── lazy_loader.gd
│   │       ├── lazy_loader.gd.uid
│   │       ├── logger.gd
│   │       ├── logger.gd.uid
│   │       ├── menu_manager.gd.uid
│   │       ├── method_maker.gd
│   │       ├── method_maker.gd.uid
│   │       ├── one_to_many.gd
│   │       ├── one_to_many.gd.uid
│   │       ├── orphan_counter.gd
│   │       ├── orphan_counter.gd.uid
│   │       ├── parameter_factory.gd
│   │       ├── parameter_factory.gd.uid
│   │       ├── parameter_handler.gd
│   │       ├── parameter_handler.gd.uid
│   │       ├── plugin.cfg
│   │       ├── printers.gd
│   │       ├── printers.gd.uid
│   │       ├── result_exporter.gd
│   │       ├── result_exporter.gd.uid
│   │       ├── script_parser.gd
│   │       ├── script_parser.gd.uid
│   │       ├── signal_watcher.gd
│   │       ├── signal_watcher.gd.uid
│   │       ├── source_code_pro.fnt
│   │       ├── spy.gd
│   │       ├── spy.gd.uid
│   │       ├── strutils.gd
│   │       ├── strutils.gd.uid
│   │       ├── stub_params.gd
│   │       ├── stub_params.gd.uid
│   │       ├── stubber.gd
│   │       ├── stubber.gd.uid
│   │       ├── summary.gd
│   │       ├── summary.gd.uid
│   │       ├── test.gd
│   │       ├── test.gd.uid
│   │       ├── test_collector.gd
│   │       ├── test_collector.gd.uid
│   │       ├── thing_counter.gd
│   │       ├── thing_counter.gd.uid
│   │       ├── utils.gd
│   │       ├── utils.gd.uid
│   │       ├── version_conversion.gd
│   │       ├── version_conversion.gd.uid
│   │       ├── version_numbers.gd
│   │       ├── version_numbers.gd.uid
│   │       ├── warnings_manager.gd
│   │       └── warnings_manager.gd.uid
│   ├── appstore.png.import
│   ├── assets/
│   │   ├── Banks/
│   │   │   ├── Dialogue_CN.bank
│   │   │   ├── Dialogue_EN.bank
│   │   │   ├── Dialogue_JP.bank
│   │   │   ├── Master.bank
│   │   │   ├── Master.strings.bank
│   │   │   ├── Music.bank
│   │   │   ├── SFX.bank
│   │   │   └── Vehicles.bank
│   │   ├── Music/
│   │   │   ├── License.txt
│   │   │   ├── jingles_SAX07.ogg
│   │   │   └── jingles_SAX07.ogg.import
│   │   └── Sounds/
│   │       ├── beltHandle1.ogg
│   │       ├── beltHandle1.ogg.import
│   │       ├── beltHandle2.ogg
│   │       ├── beltHandle2.ogg.import
│   │       ├── bookClose.ogg
│   │       ├── bookClose.ogg.import
│   │       ├── bookFlip1.ogg
│   │       ├── bookFlip1.ogg.import
│   │       ├── bookFlip2.ogg
│   │       ├── bookFlip2.ogg.import
│   │       ├── bookFlip3.ogg
│   │       ├── bookFlip3.ogg.import
│   │       ├── bookOpen.ogg
│   │       ├── bookOpen.ogg.import
│   │       ├── bookPlace1.ogg
│   │       ├── bookPlace1.ogg.import
│   │       ├── bookPlace2.ogg
│   │       ├── bookPlace2.ogg.import
│   │       ├── bookPlace3.ogg
│   │       ├── bookPlace3.ogg.import
│   │       ├── chop.ogg
│   │       ├── chop.ogg.import
│   │       ├── cloth1.ogg
│   │       ├── cloth1.ogg.import
│   │       ├── cloth2.ogg
│   │       ├── cloth2.ogg.import
│   │       ├── cloth3.ogg
│   │       ├── cloth3.ogg.import
│   │       ├── cloth4.ogg
│   │       ├── cloth4.ogg.import
│   │       ├── clothBelt.ogg
│   │       ├── clothBelt.ogg.import
│   │       ├── clothBelt2.ogg
│   │       ├── clothBelt2.ogg.import
│   │       ├── creak1.ogg
│   │       ├── creak1.ogg.import
│   │       ├── creak2.ogg
│   │       ├── creak2.ogg.import
│   │       ├── creak3.ogg
│   │       ├── creak3.ogg.import
│   │       ├── doorClose_1.ogg
│   │       ├── doorClose_1.ogg.import
│   │       ├── doorClose_2.ogg
│   │       ├── doorClose_2.ogg.import
│   │       ├── doorClose_3.ogg
│   │       ├── doorClose_3.ogg.import
│   │       ├── doorClose_4.ogg
│   │       ├── doorClose_4.ogg.import
│   │       ├── doorOpen_1.ogg
│   │       ├── doorOpen_1.ogg.import
│   │       ├── doorOpen_2.ogg
│   │       ├── doorOpen_2.ogg.import
│   │       ├── drawKnife1.ogg
│   │       ├── drawKnife1.ogg.import
│   │       ├── drawKnife2.ogg
│   │       ├── drawKnife2.ogg.import
│   │       ├── drawKnife3.ogg
│   │       ├── drawKnife3.ogg.import
│   │       ├── dropLeather.ogg
│   │       ├── dropLeather.ogg.import
│   │       ├── footstep00.ogg
│   │       ├── footstep00.ogg.import
│   │       ├── footstep01.ogg
│   │       ├── footstep01.ogg.import
│   │       ├── footstep02.ogg
│   │       ├── footstep02.ogg.import
│   │       ├── footstep03.ogg
│   │       ├── footstep03.ogg.import
│   │       ├── footstep04.ogg
│   │       ├── footstep04.ogg.import
│   │       ├── footstep05.ogg
│   │       ├── footstep05.ogg.import
│   │       ├── footstep06.ogg
│   │       ├── footstep06.ogg.import
│   │       ├── footstep07.ogg
│   │       ├── footstep07.ogg.import
│   │       ├── footstep08.ogg
│   │       ├── footstep08.ogg.import
│   │       ├── footstep09.ogg
│   │       ├── footstep09.ogg.import
│   │       ├── handleCoins.ogg
│   │       ├── handleCoins.ogg.import
│   │       ├── handleCoins2.ogg
│   │       ├── handleCoins2.ogg.import
│   │       ├── handleSmallLeather.ogg
│   │       ├── handleSmallLeather.ogg.import
│   │       ├── handleSmallLeather2.ogg
│   │       ├── handleSmallLeather2.ogg.import
│   │       ├── knifeSlice.ogg
│   │       ├── knifeSlice.ogg.import
│   │       ├── knifeSlice2.ogg
│   │       ├── knifeSlice2.ogg.import
│   │       ├── licence.txt
│   │       ├── metalClick.ogg
│   │       ├── metalClick.ogg.import
│   │       ├── metalLatch.ogg
│   │       ├── metalLatch.ogg.import
│   │       ├── metalPot1.ogg
│   │       ├── metalPot1.ogg.import
│   │       ├── metalPot2.ogg
│   │       ├── metalPot2.ogg.import
│   │       ├── metalPot3.ogg
│   │       └── metalPot3.ogg.import
│   ├── default_env.tres
│   ├── export_presets.cfg
│   ├── high_level_2D/
│   │   ├── ChangeColor.gd
│   │   ├── ChangeColor.gd.uid
│   │   ├── ChooseLanguageButton.gd
│   │   ├── ChooseLanguageButton.gd.uid
│   │   ├── Emitter.gd
│   │   ├── Emitter.gd.uid
│   │   ├── FmodNodesTest.tscn
│   │   ├── Kinematic.gd
│   │   ├── Kinematic.gd.uid
│   │   ├── SayWelcomeButton.gd
│   │   ├── SayWelcomeButton.gd.uid
│   │   ├── footstep.tscn
│   │   ├── sin_move.gd
│   │   └── sin_move.gd.uid
│   ├── high_level_3D/
│   │   ├── FPSCounter.gd
│   │   ├── FPSCounter.gd.uid
│   │   ├── World.tscn
│   │   ├── environment/
│   │   │   ├── 1x1.png.import
│   │   │   ├── Ball.tscn
│   │   │   ├── Floor.tscn
│   │   │   ├── Wall.tscn
│   │   │   ├── ball_material.tres
│   │   │   ├── box.tscn
│   │   │   ├── sin_move.gd
│   │   │   ├── sin_move.gd.uid
│   │   │   ├── soundcollider.gd
│   │   │   ├── soundcollider.gd.uid
│   │   │   └── wall_material.tres
│   │   ├── player/
│   │   │   ├── Camera.gd
│   │   │   ├── Camera.gd.uid
│   │   │   ├── Player.gd
│   │   │   ├── Player.gd.uid
│   │   │   └── Player.tscn
│   │   ├── rollingball.gd
│   │   ├── rollingball.gd.uid
│   │   ├── selfdestroy.gd
│   │   └── selfdestroy.gd.uid
│   ├── icon.png.import
│   ├── icon.svg.import
│   ├── low_level_2D/
│   │   ├── ChangeColor.gd
│   │   ├── ChangeColor.gd.uid
│   │   ├── Emitter.gd
│   │   ├── Emitter.gd.uid
│   │   ├── EnterAndLeave.gd
│   │   ├── EnterAndLeave.gd.uid
│   │   ├── EnterandLeave2.gd
│   │   ├── EnterandLeave2.gd.uid
│   │   ├── FmodScriptTest.tscn
│   │   ├── FmodTest.gd
│   │   ├── FmodTest.gd.uid
│   │   ├── LangChooseButton.gd
│   │   ├── LangChooseButton.gd.uid
│   │   ├── Listener.gd
│   │   ├── Listener.gd.uid
│   │   ├── Listener2.gd
│   │   ├── Listener2.gd.uid
│   │   ├── WelcomeButton.gd
│   │   └── WelcomeButton.gd.uid
│   ├── project.godot
│   ├── run_tests.sh
│   └── test/
│       ├── integration/
│       │   └── init
│       ├── tests.tscn
│       └── unit/
│           ├── test_bank.gd
│           ├── test_bank.gd.uid
│           ├── test_bus.gd
│           ├── test_bus.gd.uid
│           ├── test_callbacks.gd
│           ├── test_callbacks.gd.uid
│           ├── test_desc_event.gd
│           ├── test_desc_event.gd.uid
│           ├── test_event.gd
│           ├── test_event.gd.uid
│           ├── test_global.gd
│           ├── test_global.gd.uid
│           ├── test_listener.gd
│           ├── test_listener.gd.uid
│           ├── test_sound.gd
│           ├── test_sound.gd.uid
│           ├── test_vca.gd
│           └── test_vca.gd.uid
├── docs/
│   ├── .gitignore
│   ├── build.sh
│   ├── mkdocs.yml
│   ├── requirements.txt
│   ├── run.sh
│   └── src/
│       └── doc/
│           ├── advanced/
│           │   └── 1-compiling.md
│           ├── index.md
│           └── user-guide/
│               ├── 1-install.md
│               ├── 2-initialization.md
│               ├── 3-using-fmod-plugin.md
│               ├── 4-loading-banks.md
│               ├── 5-playing-events.md
│               ├── 6-listeners.md
│               ├── 7-playing-sounds.md
│               ├── 8-other-low-level-examples.md
│               └── 9-plugins.md
├── get_fmod.py
├── jni/
│   └── Application.mk
└── src/
    ├── callback/
    │   ├── event_callbacks.cpp
    │   ├── event_callbacks.h
    │   ├── file_callbacks.cpp
    │   └── file_callbacks.h
    ├── constants.h
    ├── core/
    │   ├── fmod_file.cpp
    │   ├── fmod_file.h
    │   ├── fmod_sound.cpp
    │   └── fmod_sound.h
    ├── data/
    │   ├── performance_data.cpp
    │   └── performance_data.h
    ├── fmod_cache.cpp
    ├── fmod_cache.h
    ├── fmod_logging.cpp
    ├── fmod_logging.h
    ├── fmod_server.cpp
    ├── fmod_server.h
    ├── fmod_string_names.cpp
    ├── fmod_string_names.h
    ├── helpers/
    │   ├── common.h
    │   ├── constants.h
    │   ├── current_function.h
    │   ├── files.h
    │   └── maths.h
    ├── nodes/
    │   ├── fmod_bank_loader.cpp
    │   ├── fmod_bank_loader.h
    │   ├── fmod_event_emitter.h
    │   ├── fmod_event_emitter_2d.cpp
    │   ├── fmod_event_emitter_2d.h
    │   ├── fmod_event_emitter_3d.cpp
    │   ├── fmod_event_emitter_3d.h
    │   ├── fmod_listener.h
    │   ├── fmod_listener_2d.cpp
    │   ├── fmod_listener_2d.h
    │   ├── fmod_listener_3d.cpp
    │   └── fmod_listener_3d.h
    ├── plugins/
    │   ├── ios_plugins_loader.h
    │   └── plugins_helper.h
    ├── register_types.cpp
    ├── register_types.h
    ├── resources/
    │   ├── fmod_dsp_settings.cpp
    │   ├── fmod_dsp_settings.h
    │   ├── fmod_logging_settings.cpp
    │   ├── fmod_logging_settings.h
    │   ├── fmod_plugins_settings.cpp
    │   ├── fmod_plugins_settings.h
    │   ├── fmod_settings.cpp
    │   ├── fmod_settings.h
    │   ├── fmod_software_format_settings.cpp
    │   ├── fmod_software_format_settings.h
    │   ├── fmod_sound_3d_settings.cpp
    │   └── fmod_sound_3d_settings.h
    ├── studio/
    │   ├── fmod_bank.cpp
    │   ├── fmod_bank.h
    │   ├── fmod_bus.cpp
    │   ├── fmod_bus.h
    │   ├── fmod_event.cpp
    │   ├── fmod_event.h
    │   ├── fmod_event_description.cpp
    │   ├── fmod_event_description.h
    │   ├── fmod_parameter_description.cpp
    │   ├── fmod_parameter_description.h
    │   ├── fmod_vca.cpp
    │   └── fmod_vca.h
    └── tools/
        ├── fmod_editor_export_plugin.cpp
        ├── fmod_editor_export_plugin.h
        ├── fmod_editor_plugin.cpp
        └── fmod_editor_plugin.h
Download .txt
SYMBOL INDEX (126 symbols across 51 files)

FILE: src/callback/event_callbacks.cpp
  type Callbacks (line 10) | namespace Callbacks {
    function FMOD_RESULT (line 12) | FMOD_RESULT F_CALL event_callback(FMOD_STUDIO_EVENT_CALLBACK_TYPE type...

FILE: src/callback/event_callbacks.h
  function namespace (line 7) | namespace Callbacks {

FILE: src/callback/file_callbacks.cpp
  type Callbacks (line 3) | namespace Callbacks {
    function GodotFileRunner (line 5) | GodotFileRunner* GodotFileRunner::get_singleton() {
    function FMOD_RESULT (line 24) | FMOD_RESULT GodotFileRunner::cancelReadRequest(FMOD_ASYNCREADINFO* req...
    function FMOD_RESULT (line 104) | FMOD_RESULT F_CALL godotFileOpen(const char* name, unsigned int* files...
    function FMOD_RESULT (line 116) | FMOD_RESULT F_CALL godotFileClose(void* handle, void* userdata) {
    function FMOD_RESULT (line 122) | FMOD_RESULT F_CALL godotSyncRead(FMOD_ASYNCREADINFO* info, void* userd...
    function FMOD_RESULT (line 136) | FMOD_RESULT F_CALL godotSyncCancel(FMOD_ASYNCREADINFO* info, void* use...

FILE: src/callback/file_callbacks.h
  function namespace (line 13) | namespace Callbacks {

FILE: src/core/fmod_file.h
  function namespace (line 7) | namespace godot {

FILE: src/core/fmod_sound.h
  function namespace (line 7) | namespace godot {

FILE: src/data/performance_data.h
  function namespace (line 6) | namespace godot {

FILE: src/fmod_cache.cpp
  function FMOD_GUID (line 254) | FMOD_GUID FmodCache::get_event_guid(const String& event_path) {
  function String (line 262) | String FmodCache::get_event_path(const FMOD_GUID& guid) {

FILE: src/fmod_cache.h
  function namespace (line 12) | namespace godot {

FILE: src/fmod_logging.cpp
  type godot (line 10) | namespace godot {
    function logging_init (line 13) | void logging_init() {
    function log_fmod_message (line 57) | void log_fmod_message(FMODLogLevel level, const String& message) {
    function FMOD_RESULT (line 76) | FMOD_RESULT fmod_debug_callback(FMOD_DEBUG_FLAGS flags, const char* fi...

FILE: src/fmod_logging.h
  function namespace (line 9) | namespace godot {

FILE: src/fmod_server.cpp
  function FmodServer (line 163) | FmodServer* FmodServer::get_singleton() {
  function Transform3D (line 382) | Transform3D FmodServer::get_listener_transform3d(int index) {
  function Transform2D (line 394) | Transform2D FmodServer::get_listener_transform2d(int index) {
  function Vector3 (line 406) | Vector3 FmodServer::get_listener_3d_velocity(int index) {
  function Vector2 (line 418) | Vector2 FmodServer::get_listener_2d_velocity(int index) {
  function Object (line 465) | Object* FmodServer::get_object_attached_to_listener(const int index) {
  function register_ios_dsp (line 515) | uint32_t register_ios_dsp(FMOD_SYSTEM_PTR system, FMOD_DSP_DESCRIPTION* ...
  function register_ios_codec (line 519) | uint32_t register_ios_codec(FMOD_SYSTEM_PTR system, FMOD_CODEC_DESCRIPTI...
  function register_ios_output (line 523) | uint32_t register_ios_output(FMOD_SYSTEM_PTR system, FMOD_OUTPUT_DESCRIP...
  function FMOD_GUID (line 625) | FMOD_GUID FmodServer::get_event_guid_internal(const String& event_path) {
  function String (line 629) | String FmodServer::get_event_guid(const String& event_path) {
  function String (line 633) | String FmodServer::get_event_path_internal(const FMOD_GUID& guid) {
  function String (line 637) | String FmodServer::get_event_path(const String& guid) {
  function Array (line 641) | Array FmodServer::get_all_vca() {
  function Array (line 649) | Array FmodServer::get_all_buses() {
  function Array (line 657) | Array FmodServer::get_all_event_descriptions() {
  function Array (line 665) | Array FmodServer::get_all_banks() {
  function FMOD_STUDIO_SOUND_INFO (line 896) | FMOD_STUDIO_SOUND_INFO FmodServer::get_sound_info(const String& sound_ke...
  function Array (line 928) | Array FmodServer::get_available_drivers() {
  function Dictionary (line 1040) | Dictionary FmodServer::get_global_parameter_desc_by_name(const String& p...
  function Dictionary (line 1059) | Dictionary FmodServer::get_global_parameter_desc_by_id(uint64_t paramete...
  function Array (line 1083) | Array FmodServer::get_global_parameter_desc_list() {

FILE: src/fmod_server.h
  type OneShot (line 39) | struct OneShot {
  type Listener (line 44) | struct Listener {
  type Callback (line 50) | struct Callback {
  function class (line 56) | class FmodServer : public Object {

FILE: src/fmod_string_names.cpp
  function FmodStringNames (line 16) | FmodStringNames* FmodStringNames::get_instance() {

FILE: src/fmod_string_names.h
  function class (line 10) | class FmodStringNames {

FILE: src/helpers/common.h
  function Node (line 103) | Node* node {nullptr};
  function FMOD_GUID (line 144) | static inline FMOD_GUID string_to_fmod_guid(const char* guid) {
  function String (line 154) | static inline String fmod_guid_to_string(const FMOD_GUID& guid) {
  function fmod_parameter_id_to_ulong (line 163) | static inline uint64_t fmod_parameter_id_to_ulong(const FMOD_STUDIO_PARA...

FILE: src/helpers/current_function.h
  function namespace (line 22) | namespace boost {

FILE: src/helpers/files.h
  function namespace (line 7) | namespace godot {

FILE: src/helpers/maths.h
  function namespace (line 11) | namespace godot {

FILE: src/nodes/fmod_bank_loader.cpp
  function Array (line 27) | const Array& FmodBankLoader::get_bank_paths() const {

FILE: src/nodes/fmod_bank_loader.h
  function namespace (line 7) | namespace godot {

FILE: src/nodes/fmod_event_emitter.h
  function namespace (line 20) | namespace godot {
  function Parameter (line 283) | Parameter* parameter {_find_parameter(p_name)};
  function Parameter (line 309) | Parameter* parameter {_find_parameter(p_id)};
  function FMOD_GUID (line 442) | FMOD_GUID event_guid {FmodServer::get_singleton()->get_event_guid_intern...
  function FMOD_GUID (line 461) | FMOD_GUID event_guid {string_to_fmod_guid(guid.utf8().get_data())};
  function should_load_by_name (line 617) | bool should_load_by_name {ProjectSettings::get_singleton()->get_setting(
  function String (line 630) | const String& parameter_name {parts[0]};
  function PackedStringArray (line 682) | PackedStringArray parts {p_name.trim_prefix(vformat("%s/", FmodStringNam...
  function PackedStringArray (line 717) | PackedStringArray parts {p_name.trim_prefix(vformat("%s/", FmodStringNam...
  function Parameter (line 731) | Parameter* parameter {_find_parameter(parts[0])}
  function parameter_min_value (line 766) | const float parameter_min_value {parameter_description->get_minimum()};
  function Parameter (line 837) | const Parameter& parameter {_parameters[i]};

FILE: src/nodes/fmod_event_emitter_2d.h
  function namespace (line 9) | namespace godot {

FILE: src/nodes/fmod_event_emitter_3d.h
  function namespace (line 8) | namespace godot {

FILE: src/nodes/fmod_listener.h
  function namespace (line 8) | namespace godot {

FILE: src/nodes/fmod_listener_2d.h
  function namespace (line 8) | namespace godot {

FILE: src/nodes/fmod_listener_3d.h
  function namespace (line 8) | namespace godot {

FILE: src/plugins/ios_plugins_loader.h
  type FMOD_IOS_INTERFACE (line 11) | typedef struct {

FILE: src/plugins/plugins_helper.h
  function String (line 9) | static String get_fmod_plugins_base_path(const Ref<FmodPluginsSettings>&...
  function String (line 24) | static String get_plugins_os_directory(const Ref<FmodPluginsSettings>& p...

FILE: src/register_types.cpp
  function initialize_fmod_with_settings (line 35) | void initialize_fmod_with_settings() {
  function initialize_fmod (line 50) | void initialize_fmod() {
  function initialize_fmod_module (line 68) | void initialize_fmod_module(ModuleInitializationLevel p_level) {
  function uninitialize_fmod_module (line 122) | void uninitialize_fmod_module(ModuleInitializationLevel p_level) {
  function GDExtensionBool (line 139) | GDExtensionBool GDE_EXPORT

FILE: src/resources/fmod_dsp_settings.h
  function namespace (line 6) | namespace godot {

FILE: src/resources/fmod_logging_settings.cpp
  function String (line 53) | const String& FmodLoggingSettings::get_log_file_path() const {

FILE: src/resources/fmod_logging_settings.h
  type DebugLevel (line 14) | enum DebugLevel {

FILE: src/resources/fmod_plugins_settings.cpp
  function String (line 17) | const String& FmodPluginsSettings::get_plugins_base_path() const {
  function PackedStringArray (line 25) | const PackedStringArray& FmodPluginsSettings::get_dynamic_plugin_list() ...
  function Array (line 105) | const Array& FmodPluginsSettings::get_static_plugins_methods() const {
  function String (line 121) | const String& FmodStaticPluginMethod::get_method_name() const {

FILE: src/resources/fmod_plugins_settings.h
  type Type (line 12) | enum Type {

FILE: src/resources/fmod_settings.cpp
  function String (line 45) | const String& FmodGeneralSettings::get_banks_path() const {

FILE: src/resources/fmod_settings.h
  function namespace (line 8) | namespace godot {

FILE: src/resources/fmod_software_format_settings.h
  function namespace (line 8) | namespace godot {

FILE: src/resources/fmod_sound_3d_settings.h
  function namespace (line 6) | namespace godot {

FILE: src/studio/fmod_bank.cpp
  function Array (line 48) | Array FmodBank::get_description_list() const {
  function Array (line 56) | Array FmodBank::get_bus_list() const {
  function Array (line 64) | Array FmodBank::get_vca_list() const {
  function String (line 153) | const String& FmodBank::get_godot_res_path() const {

FILE: src/studio/fmod_bank.h
  function namespace (line 11) | namespace godot {

FILE: src/studio/fmod_bus.h
  function namespace (line 7) | namespace godot {

FILE: src/studio/fmod_event.cpp
  function FMOD_STUDIO_PLAYBACK_STATE (line 122) | FMOD_STUDIO_PLAYBACK_STATE FmodEvent::get_playback_state() const {
  function Transform2D (line 199) | Transform2D FmodEvent::get_2d_attributes() const {
  function Transform3D (line 212) | Transform3D FmodEvent::get_3d_attributes() const {
  function Callable (line 247) | const Callable& FmodEvent::get_callback() const {
  function String (line 251) | const String& FmodEvent::get_programmers_callback_sound_key() const {

FILE: src/studio/fmod_event_description.cpp
  function Array (line 59) | Array FmodEventDescription::get_instance_list() {
  function Array (line 133) | Array FmodEventDescription::get_min_max_distance() {
  function Array (line 187) | Array FmodEventDescription::get_parameters() const {
  function String (line 195) | String FmodEventDescription::get_parameter_label_by_id(uint64_t id, int ...
  function String (line 208) | String FmodEventDescription::get_parameter_label_by_name(const String& p...
  function String (line 221) | String FmodEventDescription::get_parameter_label_by_index(int index, int...
  function PackedStringArray (line 234) | PackedStringArray FmodEventDescription::get_parameter_labels_by_id(uint6...
  function PackedStringArray (line 249) | PackedStringArray FmodEventDescription::get_parameter_labels_by_name(con...
  function PackedStringArray (line 264) | PackedStringArray FmodEventDescription::get_parameter_labels_by_index(in...
  function Dictionary (line 279) | Dictionary FmodEventDescription::get_user_property(const String& name) {
  function Dictionary (line 304) | Dictionary FmodEventDescription::user_property_by_index(int index) {

FILE: src/studio/fmod_event_description.h
  function namespace (line 9) | namespace godot {

FILE: src/studio/fmod_parameter_description.cpp
  function String (line 7) | const String& FmodParameterDescription::get_name() const {

FILE: src/studio/fmod_parameter_description.h
  function namespace (line 7) | namespace godot {

FILE: src/studio/fmod_vca.h
  function namespace (line 8) | namespace godot {

FILE: src/tools/fmod_editor_export_plugin.cpp
  function String (line 182) | String FmodEditorExportPlugin::_get_name() const {
  function PackedStringArray (line 207) | PackedStringArray FmodEditorExportPlugin::_get_libraries_to_export(const...

FILE: src/tools/fmod_editor_export_plugin.h
  function namespace (line 10) | namespace godot {

FILE: src/tools/fmod_editor_plugin.h
  function namespace (line 11) | namespace godot {
Condensed preview — 560 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,305K chars).
[
  {
    "path": ".clang-format",
    "chars": 3144,
    "preview": "---\nBasedOnStyle: LLVM\nAccessModifierOffset: -4\nAlignAfterOpenBracket: BlockIndent\nAlignEscapedNewlines: Left\nAlignOpera"
  },
  {
    "path": ".gitattributes",
    "chars": 306,
    "preview": "# Normalize EOL for all files that Git considers text files.\n* text=auto eol=lf\n\n# Ignore some files when exporting to a"
  },
  {
    "path": ".github/actions/create-android-plugin/action.yaml",
    "chars": 593,
    "preview": "name: Create Fmod native build\ndescription: Creates fmod native build for a specific platform\nruns:\n  using: composite\n "
  },
  {
    "path": ".github/actions/create-native-build/action.yaml",
    "chars": 4624,
    "preview": "name: Create Fmod native build\ndescription: Creates fmod native build for a specific platform\ninputs:\n  platform:\n    de"
  },
  {
    "path": ".github/workflows/check_pr.yml",
    "chars": 7371,
    "preview": "name: 🌈 Check Pull Request\non:\n  pull_request:\n    types: [opened, synchronize, reopened]\n  pull_request_target:\n    typ"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 9907,
    "preview": "name: 🌈 Release\non:\n  push:\n    tags:\n      - '\\d+.\\d+.\\d+-\\d+.\\d+.\\d+'\n\n# Global Settings\nenv:\n  GODOT_VERSION: 4.5\n  N"
  },
  {
    "path": ".gitignore",
    "chars": 2584,
    "preview": "\n# Created by https://www.gitignore.io/api/clion,cmake,scons\n# Edit at https://www.gitignore.io/?templates=clion,cmake,s"
  },
  {
    "path": ".gitmodules",
    "chars": 90,
    "preview": "[submodule \"godot-cpp\"]\n\tpath = godot-cpp\n\turl = https://github.com/godotengine/godot-cpp\n"
  },
  {
    "path": ".readthedocs.yml",
    "chars": 489,
    "preview": "# .readthedocs.yml\n# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html fo"
  },
  {
    "path": "Android.mk",
    "chars": 1487,
    "preview": "# Android.mk\nLOCAL_PATH := $(call my-dir)\n\ninclude $(CLEAR_VARS)\nLOCAL_MODULE := fmod-core-prebuilt\nLOCAL_SRC_FILES := ."
  },
  {
    "path": "LICENSE",
    "chars": 1085,
    "preview": "MIT License\n\nCopyright (c) 2019 Utopia-Rise and Alex Fonseka\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "README.md",
    "chars": 3369,
    "preview": "![logo](docs/src/doc/assets/fmod-gdextension-logo.png)\n\n[![🌈 Build](https://github.com/utopia-rise/fmod-gdextension/acti"
  },
  {
    "path": "SConstruct",
    "chars": 7652,
    "preview": "#!/usr/bin/env python\nimport os\nimport shutil\nimport subprocess\n\nfrom SCons.Script import SConscript, ARGUMENTS, Action,"
  },
  {
    "path": "android-plugin/.gitignore",
    "chars": 129,
    "preview": "*.iml\n.gradle\n/local.properties\n/.idea/\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n.cxx\nlocal.properties\nlibrary/li"
  },
  {
    "path": "android-plugin/build.gradle.kts",
    "chars": 237,
    "preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\nplugins {\n    id(\"co"
  },
  {
    "path": "android-plugin/gradle/wrapper/gradle-wrapper.properties",
    "chars": 221,
    "preview": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributi"
  },
  {
    "path": "android-plugin/gradle.properties",
    "chars": 1358,
    "preview": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will ov"
  },
  {
    "path": "android-plugin/gradlew",
    "chars": 8472,
    "preview": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "android-plugin/gradlew.bat",
    "chars": 2776,
    "preview": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \""
  },
  {
    "path": "android-plugin/library/.gitignore",
    "chars": 6,
    "preview": "/build"
  },
  {
    "path": "android-plugin/library/build.gradle.kts",
    "chars": 1861,
    "preview": "\nplugins {\n    id(\"com.android.library\")\n    id(\"org.jetbrains.kotlin.android\")\n}\n\nval pluginName = \"fmod\"\nval pluginPac"
  },
  {
    "path": "android-plugin/library/src/main/AndroidManifest.xml",
    "chars": 391,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          xm"
  },
  {
    "path": "android-plugin/library/src/main/kotlin/com/utopiarise/godot/fmod/android/plugin/FmodPlugin.kt",
    "chars": 841,
    "preview": "package com.utopiarise.godot.fmod.android.plugin\n\nimport android.app.Activity\nimport android.view.View\nimport org.fmod.F"
  },
  {
    "path": "android-plugin/library/src/main/resources/fmod-android-license.txt",
    "chars": 1303,
    "preview": "Copyright (C) 2010 The Android Open Source Project All rights reserved.\n\nRedistribution and use in source and binary for"
  },
  {
    "path": "android-plugin/settings.gradle.kts",
    "chars": 349,
    "preview": "pluginManagement {\n    repositories {\n        google()\n        mavenCentral()\n        gradlePluginPortal()\n    }\n}\ndepen"
  },
  {
    "path": "demo/.gitattributes",
    "chars": 80,
    "preview": "# Normalize EOL for all files that Git considers text files.\n* text=auto eol=lf\n"
  },
  {
    "path": "demo/.gitignore",
    "chars": 291,
    "preview": "\n# Godot 4+ specific ignores\n.godot/\n\n# Godot-specific ignores\n.import/\nexport.cfg\nexport_credentials.cfg\n\n# Imported tr"
  },
  {
    "path": "demo/.gutconfig.json",
    "chars": 735,
    "preview": "{\n \"background_color\": \"262626ff\",\n \"compact_mode\": false,\n \"configured_dirs\": [\n  \"res://test/unit\"\n ],\n \"dirs\": [\n  \"r"
  },
  {
    "path": "demo/addons/fmod/.gitignore",
    "chars": 50,
    "preview": "*.dll\n*.a\n*.dylib\n*.so\n*.so.*\n*.xcframework\n!libs/"
  },
  {
    "path": "demo/addons/fmod/FmodAndroidExportPlugin.gd",
    "chars": 498,
    "preview": "@tool\nclass_name FmodAndroidExportPlugin extends EditorExportPlugin\n\nvar plugin_name: String = \"fmod\"\n\nfunc _supports_pl"
  },
  {
    "path": "demo/addons/fmod/FmodAndroidExportPlugin.gd.uid",
    "chars": 20,
    "preview": "uid://cle6f2srp4yun\n"
  },
  {
    "path": "demo/addons/fmod/FmodManager.gd",
    "chars": 567,
    "preview": "@tool\nextends Node\n\nvar performance_display: PerformancesDisplay\n\nfunc _ready():\n\tprocess_mode = PROCESS_MODE_ALWAYS\n\tpe"
  },
  {
    "path": "demo/addons/fmod/FmodManager.gd.uid",
    "chars": 20,
    "preview": "uid://cds10pm7hwn3p\n"
  },
  {
    "path": "demo/addons/fmod/FmodPlugin.gd",
    "chars": 3351,
    "preview": "@tool\nclass_name FmodPlugin extends EditorPlugin\n\n\nconst ADDON_PATH: StringName = &\"res://addons/fmod\"\nconst FmodManager"
  },
  {
    "path": "demo/addons/fmod/FmodPlugin.gd.uid",
    "chars": 20,
    "preview": "uid://cwsif6rhp50p5\n"
  },
  {
    "path": "demo/addons/fmod/fmod.gdextension",
    "chars": 3767,
    "preview": "[configuration]\nentry_symbol = \"fmod_library_init\"\ncompatibility_minimum = 4.5\n\n[libraries]\nwindows.editor.x86_64 = \"res"
  },
  {
    "path": "demo/addons/fmod/fmod.gdextension.uid",
    "chars": 20,
    "preview": "uid://dq17s7r52klxe\n"
  },
  {
    "path": "demo/addons/fmod/icons/bank_icon.svg.import",
    "chars": 1071,
    "preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://o2chsr07oeqs\"\npath=\"res://.godot/imported/bank_icon.sv"
  },
  {
    "path": "demo/addons/fmod/icons/bus_icon.svg.import",
    "chars": 1069,
    "preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dj1kag4aeg58t\"\npath=\"res://.godot/imported/bus_icon.sv"
  },
  {
    "path": "demo/addons/fmod/icons/c_parameter_icon.svg.import",
    "chars": 1093,
    "preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cmvcqfsl167te\"\npath=\"res://.godot/imported/c_parameter"
  },
  {
    "path": "demo/addons/fmod/icons/d_parameter_icon.svg.import",
    "chars": 1093,
    "preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://dgna04txtwnyb\"\npath=\"res://.godot/imported/d_parameter"
  },
  {
    "path": "demo/addons/fmod/icons/event_icon.svg.import",
    "chars": 1075,
    "preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cmpgmbn3y4svl\"\npath=\"res://.godot/imported/event_icon."
  },
  {
    "path": "demo/addons/fmod/icons/fmod_emitter.png.import",
    "chars": 958,
    "preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://cotpb54utx6d6\"\npath=\"res://.godot/imported/fmod_emitte"
  },
  {
    "path": "demo/addons/fmod/icons/fmod_icon.svg.import",
    "chars": 1072,
    "preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://bwqq5q7kodk40\"\npath=\"res://.godot/imported/fmod_icon.s"
  },
  {
    "path": "demo/addons/fmod/icons/snapshot_icon.svg.import",
    "chars": 1084,
    "preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://b4jxbh86chubi\"\npath=\"res://.godot/imported/snapshot_ic"
  },
  {
    "path": "demo/addons/fmod/icons/vca_icon.svg.import",
    "chars": 1069,
    "preview": "[remap]\n\nimporter=\"texture\"\ntype=\"CompressedTexture2D\"\nuid=\"uid://crsj4jjaeq87a\"\npath=\"res://.godot/imported/vca_icon.sv"
  },
  {
    "path": "demo/addons/fmod/libs/android/arm64/CopyPast_Fmod_Libs_Here.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "demo/addons/fmod/libs/iOS/CopyPast_Fmod_Libs_Here.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "demo/addons/fmod/libs/linux/CopyPast_Fmod_Libs_Here.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "demo/addons/fmod/libs/macos/CopyPast_Fmod_Libs_Here.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "demo/addons/fmod/libs/macos/libGodotFmod.macos.editor.framework/Info.plist",
    "chars": 790,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "demo/addons/fmod/libs/macos/libGodotFmod.macos.template_debug.framework/Info.plist",
    "chars": 805,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "demo/addons/fmod/libs/macos/libGodotFmod.macos.template_release.framework/Info.plist",
    "chars": 809,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "demo/addons/fmod/libs/windows/CopyPast_Fmod_Libs_Here.txt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "demo/addons/fmod/plugin.cfg",
    "chars": 188,
    "preview": "[plugin]\n\nname=\"FMOD GDExtension\"\ndescription=\"FMOD GDExtension for Godot Engine 4.5\"\nauthor=\"Utopia-rise, Tristan Gresp"
  },
  {
    "path": "demo/addons/fmod/tool/FmodBankDatabase.gd",
    "chars": 1420,
    "preview": "extends Node\n\nclass_name FmodBankDatabase\n\n\nstatic var banks := Array()\nconst MASTER_STRINGS_BANK_NAME = \"Master.strings"
  },
  {
    "path": "demo/addons/fmod/tool/FmodBankDatabase.gd.uid",
    "chars": 20,
    "preview": "uid://dovuikgbkylhi\n"
  },
  {
    "path": "demo/addons/fmod/tool/inspectors/FmodBankLoaderPropertyInspectorPlugin.gd",
    "chars": 805,
    "preview": "class_name FmodBankLoaderPropertyInspectorPlugin extends EditorInspectorPlugin\n\nstatic var bank_icon = load(\"res://addon"
  },
  {
    "path": "demo/addons/fmod/tool/inspectors/FmodBankLoaderPropertyInspectorPlugin.gd.uid",
    "chars": 19,
    "preview": "uid://tnljjxahubam\n"
  },
  {
    "path": "demo/addons/fmod/tool/inspectors/FmodEmitterPropertyInspectorPlugin.gd",
    "chars": 1083,
    "preview": "class_name FmodEmitterPropertyInspectorPlugin extends EditorInspectorPlugin\n\nvar _open_project_explorer_callable: Callab"
  },
  {
    "path": "demo/addons/fmod/tool/inspectors/FmodEmitterPropertyInspectorPlugin.gd.uid",
    "chars": 20,
    "preview": "uid://co1ktq45h26wx\n"
  },
  {
    "path": "demo/addons/fmod/tool/performances/PerformancesDisplay.gd",
    "chars": 2845,
    "preview": "class_name PerformancesDisplay extends Node\n\n\nconst CORE_CPU_DSP_CATEGORY = \"FMOD [Core]/Cpu DSP\"\nconst CORE_CPU_GEOMETR"
  },
  {
    "path": "demo/addons/fmod/tool/performances/PerformancesDisplay.gd.uid",
    "chars": 20,
    "preview": "uid://bc0uajlvc0u00\n"
  },
  {
    "path": "demo/addons/fmod/tool/property_editors/FmodBankPathEditorProperty.gd",
    "chars": 3307,
    "preview": "class_name FmodBankPathEditorProperty extends EditorProperty\n\nvar path_property_name := \"bank_paths\"\n\nvar ui: Control\nva"
  },
  {
    "path": "demo/addons/fmod/tool/property_editors/FmodBankPathEditorProperty.gd.uid",
    "chars": 20,
    "preview": "uid://cxyd4qioylvgr\n"
  },
  {
    "path": "demo/addons/fmod/tool/property_editors/FmodBankPathsPropertyEditorUi.tscn",
    "chars": 1599,
    "preview": "[gd_scene load_steps=2 format=3 uid=\"uid://dtlwk8wdeal3h\"]\n\n[ext_resource type=\"Texture2D\" uid=\"uid://o2chsr07oeqs\" path"
  },
  {
    "path": "demo/addons/fmod/tool/property_editors/FmodEventEditorProperty.gd",
    "chars": 4749,
    "preview": "@tool class_name FmodEventEditorProperty extends FmodPathEditorProperty\n\n\nstatic var EVENT_PARAMETER_PREFIX_FOR_PROPERTI"
  },
  {
    "path": "demo/addons/fmod/tool/property_editors/FmodEventEditorProperty.gd.uid",
    "chars": 20,
    "preview": "uid://b32x60k0th8td\n"
  },
  {
    "path": "demo/addons/fmod/tool/property_editors/FmodEventEditorProperty.tscn",
    "chars": 453,
    "preview": "[gd_scene load_steps=3 format=3 uid=\"uid://cowfthogh1n7i\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://cujo3xq0erren\" p"
  },
  {
    "path": "demo/addons/fmod/tool/property_editors/FmodGuidAndPathPropertyEditorUi.gd",
    "chars": 394,
    "preview": "@tool class_name FmodGuidAndPathPropertyEditorUi extends HBoxContainer\n\n\nfunc set_callables(window_callable: Callable, p"
  },
  {
    "path": "demo/addons/fmod/tool/property_editors/FmodGuidAndPathPropertyEditorUi.gd.uid",
    "chars": 19,
    "preview": "uid://3xn18ci172v4\n"
  },
  {
    "path": "demo/addons/fmod/tool/property_editors/FmodGuidAndPathPropertyEditorUi.tscn",
    "chars": 977,
    "preview": "[gd_scene load_steps=3 format=3 uid=\"uid://hy04frgfhtgu\"]\n\n[ext_resource type=\"Script\" uid=\"uid://3xn18ci172v4\" path=\"re"
  },
  {
    "path": "demo/addons/fmod/tool/property_editors/FmodPathEditorProperty.gd",
    "chars": 1480,
    "preview": "@tool class_name FmodPathEditorProperty extends EditorProperty\n\nvar ui: Control\nvar guid_property: String\nvar path_prope"
  },
  {
    "path": "demo/addons/fmod/tool/property_editors/FmodPathEditorProperty.gd.uid",
    "chars": 19,
    "preview": "uid://qshng8csi2fr\n"
  },
  {
    "path": "demo/addons/fmod/tool/property_editors/FmodPathEditorProperty.tscn",
    "chars": 671,
    "preview": "[gd_scene load_steps=3 format=3 uid=\"uid://cujo3xq0erren\"]\n\n[ext_resource type=\"Script\" uid=\"uid://qshng8csi2fr\" path=\"r"
  },
  {
    "path": "demo/addons/fmod/tool/ui/EventParametersDisplay.gd",
    "chars": 1004,
    "preview": "@tool class_name EventParametersDisplay extends ScrollContainer\n\nstatic var parameter_display_scene: PackedScene = load("
  },
  {
    "path": "demo/addons/fmod/tool/ui/EventParametersDisplay.gd.uid",
    "chars": 19,
    "preview": "uid://7relkis52fsu\n"
  },
  {
    "path": "demo/addons/fmod/tool/ui/EventParametersDisplay.tscn",
    "chars": 594,
    "preview": "[gd_scene load_steps=2 format=3 uid=\"uid://cppeyr1ke5wre\"]\n\n[ext_resource type=\"Script\" uid=\"uid://7relkis52fsu\" path=\"r"
  },
  {
    "path": "demo/addons/fmod/tool/ui/EventParametersWindow.tscn",
    "chars": 325,
    "preview": "[gd_scene load_steps=2 format=3 uid=\"uid://skp8awewyl85\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://cppeyr1ke5wre\" pa"
  },
  {
    "path": "demo/addons/fmod/tool/ui/EventPlayControls.gd",
    "chars": 1347,
    "preview": "@tool\nextends PanelContainer\n\n@export var play_button : Button\n@export var stop_button : Button\n@export var fade_out_tog"
  },
  {
    "path": "demo/addons/fmod/tool/ui/EventPlayControls.gd.uid",
    "chars": 19,
    "preview": "uid://vgmq7hfrbddw\n"
  },
  {
    "path": "demo/addons/fmod/tool/ui/FmodBankExplorer.gd",
    "chars": 8401,
    "preview": "@tool class_name FmodBankExplorer extends Window\n\nenum ToDisplayFlags {\n\tBUSES = 1,\n\tVCA = 2,\n\tEVENTS = 4\n}\n\nstatic var "
  },
  {
    "path": "demo/addons/fmod/tool/ui/FmodBankExplorer.gd.uid",
    "chars": 20,
    "preview": "uid://b5xgbibc3amtk\n"
  },
  {
    "path": "demo/addons/fmod/tool/ui/FmodBankExplorer.tscn",
    "chars": 15243,
    "preview": "[gd_scene load_steps=17 format=3 uid=\"uid://nr38urn226al\"]\n\n[ext_resource type=\"Script\" uid=\"uid://b5xgbibc3amtk\" path=\""
  },
  {
    "path": "demo/addons/fmod/tool/ui/ParameterDisplay.gd",
    "chars": 2059,
    "preview": "@tool class_name ParameterDisplay extends MarginContainer\n\nvar event_description: FmodEventDescription\nvar parameter: Fm"
  },
  {
    "path": "demo/addons/fmod/tool/ui/ParameterDisplay.gd.uid",
    "chars": 19,
    "preview": "uid://ve6g43nb1hdd\n"
  },
  {
    "path": "demo/addons/fmod/tool/ui/ParameterDisplay.tscn",
    "chars": 4498,
    "preview": "[gd_scene load_steps=2 format=3 uid=\"uid://bfdldojk5i6u3\"]\n\n[ext_resource type=\"Script\" uid=\"uid://ve6g43nb1hdd\" path=\"r"
  },
  {
    "path": "demo/addons/fmod/tool/ui/TestFmodBankExplorer.tscn",
    "chars": 594,
    "preview": "[gd_scene load_steps=2 format=3 uid=\"uid://f4i35731qm63\"]\n\n[ext_resource type=\"PackedScene\" uid=\"uid://nr38urn226al\" pat"
  },
  {
    "path": "demo/addons/gut/GutScene.gd",
    "chars": 3570,
    "preview": "extends Node2D\n# ##############################################################################\n# This is a wrapper arou"
  },
  {
    "path": "demo/addons/gut/GutScene.gd.uid",
    "chars": 20,
    "preview": "uid://bw7tukh738kw1\n"
  },
  {
    "path": "demo/addons/gut/GutScene.tscn",
    "chars": 673,
    "preview": "[gd_scene load_steps=4 format=3 uid=\"uid://m28heqtswbuq\"]\n\n[ext_resource type=\"Script\" uid=\"uid://bw7tukh738kw1\" path=\"r"
  },
  {
    "path": "demo/addons/gut/LICENSE.md",
    "chars": 1107,
    "preview": "The MIT License (MIT)\n=====================\n\nCopyright (c) 2018 Tom \"Butch\" Wesley\n\nPermission is hereby granted, free o"
  },
  {
    "path": "demo/addons/gut/UserFileViewer.gd",
    "chars": 1090,
    "preview": "extends Window\n\n@onready var rtl = $TextDisplay/RichTextLabel\n\nfunc _get_file_as_text(path):\n\tvar to_return = null\n\tvar "
  },
  {
    "path": "demo/addons/gut/UserFileViewer.gd.uid",
    "chars": 19,
    "preview": "uid://x51wilphva3d\n"
  },
  {
    "path": "demo/addons/gut/UserFileViewer.tscn",
    "chars": 3433,
    "preview": "[gd_scene load_steps=2 format=3 uid=\"uid://bsm7wtt1gie4v\"]\n\n[ext_resource type=\"Script\" uid=\"uid://x51wilphva3d\" path=\"r"
  },
  {
    "path": "demo/addons/gut/autofree.gd",
    "chars": 2742,
    "preview": "# ##############################################################################\n#(G)odot (U)nit (T)est class\n#\n# ######"
  },
  {
    "path": "demo/addons/gut/autofree.gd.uid",
    "chars": 20,
    "preview": "uid://bxjfriqxgwe0r\n"
  },
  {
    "path": "demo/addons/gut/awaiter.gd",
    "chars": 5660,
    "preview": "extends Node\n\nclass AwaitLogger:\n\tvar _time_waited = 0.0\n\tvar logger = GutUtils.get_logger()\n\tvar waiting_on = \"nothing\""
  },
  {
    "path": "demo/addons/gut/awaiter.gd.uid",
    "chars": 20,
    "preview": "uid://ccu4ww35edtdi\n"
  },
  {
    "path": "demo/addons/gut/cli/change_project_warnings.gd",
    "chars": 8325,
    "preview": "extends SceneTree\n\nvar Optparse = load('res://addons/gut/cli/optparse.gd')\nvar WarningsManager = load(\"res://addons/gut/"
  },
  {
    "path": "demo/addons/gut/cli/change_project_warnings.gd.uid",
    "chars": 19,
    "preview": "uid://1pauyfnd1cre\n"
  },
  {
    "path": "demo/addons/gut/cli/gut_cli.gd",
    "chars": 13748,
    "preview": "extends Node\n\nvar Optparse = load('res://addons/gut/cli/optparse.gd')\nvar Gut = load('res://addons/gut/gut.gd')\nvar GutR"
  },
  {
    "path": "demo/addons/gut/cli/gut_cli.gd.uid",
    "chars": 20,
    "preview": "uid://bhuudqinp4bth\n"
  },
  {
    "path": "demo/addons/gut/cli/optparse.gd",
    "chars": 23678,
    "preview": "## Parses command line arguments, as one might expect.\n##\n## Parses command line arguments with a bunch of options inclu"
  },
  {
    "path": "demo/addons/gut/cli/optparse.gd.uid",
    "chars": 20,
    "preview": "uid://c8m4fojwln6bq\n"
  },
  {
    "path": "demo/addons/gut/collected_script.gd",
    "chars": 5399,
    "preview": "# ------------------------------------------------------------------------------\n# This holds all the meta information f"
  },
  {
    "path": "demo/addons/gut/collected_script.gd.uid",
    "chars": 20,
    "preview": "uid://bjjcnr1oqvag6\n"
  },
  {
    "path": "demo/addons/gut/collected_test.gd",
    "chars": 3103,
    "preview": "# ------------------------------------------------------------------------------\n# Used to keep track of info about each"
  },
  {
    "path": "demo/addons/gut/collected_test.gd.uid",
    "chars": 20,
    "preview": "uid://cl854f1m26a2a\n"
  },
  {
    "path": "demo/addons/gut/comparator.gd",
    "chars": 3315,
    "preview": "var _strutils = GutUtils.Strutils.new()\nvar _max_length = 100\nvar _should_compare_int_to_float = true\n\nconst MISSING = '"
  },
  {
    "path": "demo/addons/gut/comparator.gd.uid",
    "chars": 20,
    "preview": "uid://bohry7fhscy7y\n"
  },
  {
    "path": "demo/addons/gut/compare_result.gd",
    "chars": 1169,
    "preview": "var _are_equal = false\nvar are_equal = false :\n\tget:\n\t\treturn get_are_equal()\n\tset(val):\n\t\tset_are_equal(val)\n\nvar _summ"
  },
  {
    "path": "demo/addons/gut/compare_result.gd.uid",
    "chars": 20,
    "preview": "uid://cow1xqmqqvn4e\n"
  },
  {
    "path": "demo/addons/gut/diff_formatter.gd",
    "chars": 1533,
    "preview": "var _strutils = GutUtils.Strutils.new()\nconst INDENT = '    '\nvar _max_to_display = 30\nconst ABSOLUTE_MAX_DISPLAYED = 10"
  },
  {
    "path": "demo/addons/gut/diff_formatter.gd.uid",
    "chars": 20,
    "preview": "uid://ch2km05phxacd\n"
  },
  {
    "path": "demo/addons/gut/diff_tool.gd",
    "chars": 3562,
    "preview": "extends 'res://addons/gut/compare_result.gd'\nconst INDENT = '    '\nenum {\n\tDEEP,\n\tSIMPLE\n}\n\nvar _strutils = GutUtils.Str"
  },
  {
    "path": "demo/addons/gut/diff_tool.gd.uid",
    "chars": 20,
    "preview": "uid://beoxokvl1hjs8\n"
  },
  {
    "path": "demo/addons/gut/double_templates/function_template.txt",
    "chars": 277,
    "preview": "{func_decleration}\n\tif(__gutdbl == null):\n\t\treturn\n\n\t__gutdbl.spy_on('{method_name}', {param_array})\n\tif(__gutdbl.is_stu"
  },
  {
    "path": "demo/addons/gut/double_templates/init_template.txt",
    "chars": 93,
    "preview": "{func_decleration}:\n\tsuper({super_params})\n\t__gutdbl.spy_on('{method_name}', {param_array})\n\n"
  },
  {
    "path": "demo/addons/gut/double_templates/script_template.txt",
    "chars": 1204,
    "preview": "# ##############################################################################\n# Gut Doubled Script\n# ################"
  },
  {
    "path": "demo/addons/gut/double_tools.gd",
    "chars": 1985,
    "preview": "var thepath = ''\nvar subpath = ''\nvar from_singleton = null\nvar is_partial = null\n\nvar double_ref : WeakRef = null\nvar s"
  },
  {
    "path": "demo/addons/gut/double_tools.gd.uid",
    "chars": 19,
    "preview": "uid://tr4khoco1hef\n"
  },
  {
    "path": "demo/addons/gut/doubler.gd",
    "chars": 9322,
    "preview": "extends RefCounted\n\n\nvar _base_script_text = GutUtils.get_file_as_text('res://addons/gut/double_templates/script_templat"
  },
  {
    "path": "demo/addons/gut/doubler.gd.uid",
    "chars": 20,
    "preview": "uid://cpy013l0wqwmg\n"
  },
  {
    "path": "demo/addons/gut/dynamic_gdscript.gd",
    "chars": 1154,
    "preview": "@tool\nvar default_script_name_no_extension = 'gut_dynamic_script'\nvar default_script_resource_path = 'res://addons/gut/n"
  },
  {
    "path": "demo/addons/gut/dynamic_gdscript.gd.uid",
    "chars": 20,
    "preview": "uid://cnbjsrik0p5uf\n"
  },
  {
    "path": "demo/addons/gut/editor_caret_context_notifier.gd",
    "chars": 7616,
    "preview": "@tool\nextends Node\n# ##############################################################################\n#\n# Watches script e"
  },
  {
    "path": "demo/addons/gut/editor_caret_context_notifier.gd.uid",
    "chars": 20,
    "preview": "uid://c110s7a32x4su\n"
  },
  {
    "path": "demo/addons/gut/error_tracker.gd",
    "chars": 5238,
    "preview": "extends Logger\nclass_name GutErrorTracker\n\n# ---------------------------------------------------------------------------"
  },
  {
    "path": "demo/addons/gut/error_tracker.gd.uid",
    "chars": 19,
    "preview": "uid://35kxgqotjmlu\n"
  },
  {
    "path": "demo/addons/gut/fonts/OFL.txt",
    "chars": 4426,
    "preview": "Copyright (c) 2009, Mark Simonson (http://www.ms-studio.com, mark@marksimonson.com),\nwith Reserved Font Name Anonymous P"
  },
  {
    "path": "demo/addons/gut/gui/EditorRadioButton.tres",
    "chars": 542,
    "preview": "[gd_resource type=\"Theme\" load_steps=3 format=3 uid=\"uid://dssgvu257o1si\"]\n\n[sub_resource type=\"StyleBoxFlat\" id=\"StyleB"
  },
  {
    "path": "demo/addons/gut/gui/GutBottomPanel.gd",
    "chars": 15155,
    "preview": "@tool\nextends Control\n\nvar GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')\nvar GutConfigGui = load('re"
  },
  {
    "path": "demo/addons/gut/gui/GutBottomPanel.gd.uid",
    "chars": 20,
    "preview": "uid://dtvnb0xatk0my\n"
  },
  {
    "path": "demo/addons/gut/gui/GutBottomPanel.tscn",
    "chars": 10099,
    "preview": "[gd_scene load_steps=10 format=3 uid=\"uid://b3bostcslstem\"]\n\n[ext_resource type=\"Script\" uid=\"uid://dtvnb0xatk0my\" path="
  },
  {
    "path": "demo/addons/gut/gui/GutControl.gd",
    "chars": 8935,
    "preview": "@tool\nextends Control\n\nconst RUNNER_JSON_PATH = 'res://.gut_editor_config.json'\n\nvar GutConfig = load('res://addons/gut/"
  },
  {
    "path": "demo/addons/gut/gui/GutControl.gd.uid",
    "chars": 20,
    "preview": "uid://cqlvpwidawld6\n"
  },
  {
    "path": "demo/addons/gut/gui/GutControl.tscn",
    "chars": 1777,
    "preview": "[gd_scene load_steps=2 format=3 uid=\"uid://4jb53yqktyfg\"]\n\n[ext_resource type=\"Script\" uid=\"uid://cqlvpwidawld6\" path=\"r"
  },
  {
    "path": "demo/addons/gut/gui/GutEditorWindow.gd",
    "chars": 2054,
    "preview": "@tool\nextends Window\n\n\nvar GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')\n\n@onready var _chk_always_o"
  },
  {
    "path": "demo/addons/gut/gui/GutEditorWindow.gd.uid",
    "chars": 20,
    "preview": "uid://crp2af6k4nmf5\n"
  },
  {
    "path": "demo/addons/gut/gui/GutEditorWindow.tscn",
    "chars": 4351,
    "preview": "[gd_scene load_steps=10 format=3 uid=\"uid://dnnvwlplf1km7\"]\n\n[ext_resource type=\"Script\" uid=\"uid://crp2af6k4nmf5\" path="
  },
  {
    "path": "demo/addons/gut/gui/GutLogo.tscn",
    "chars": 1269,
    "preview": "[gd_scene load_steps=4 format=3 uid=\"uid://bjkn8mhx2fmt1\"]\n\n[ext_resource type=\"Script\" uid=\"uid://b8lvgepb64m8t\" path=\""
  },
  {
    "path": "demo/addons/gut/gui/GutRunner.gd",
    "chars": 7604,
    "preview": "# ##############################################################################\n# This class joins together GUT, GUT Gu"
  },
  {
    "path": "demo/addons/gut/gui/GutRunner.gd.uid",
    "chars": 19,
    "preview": "uid://eg8k46gd42a4\n"
  },
  {
    "path": "demo/addons/gut/gui/GutRunner.tscn",
    "chars": 477,
    "preview": "[gd_scene load_steps=3 format=3 uid=\"uid://bqy3ikt6vu4b5\"]\n\n[ext_resource type=\"Script\" uid=\"uid://eg8k46gd42a4\" path=\"r"
  },
  {
    "path": "demo/addons/gut/gui/GutSceneTheme.tres",
    "chars": 293,
    "preview": "[gd_resource type=\"Theme\" load_steps=2 format=3 uid=\"uid://cstkhwkpajvqu\"]\n\n[ext_resource type=\"FontFile\" uid=\"uid://c6c"
  },
  {
    "path": "demo/addons/gut/gui/MinGui.tscn",
    "chars": 5218,
    "preview": "[gd_scene load_steps=5 format=3 uid=\"uid://cnqqdfsn80ise\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://cstkhwkpajvqu\" path=\"r"
  },
  {
    "path": "demo/addons/gut/gui/NormalGui.tscn",
    "chars": 7392,
    "preview": "[gd_scene load_steps=5 format=3 uid=\"uid://duxblir3vu8x7\"]\n\n[ext_resource type=\"Theme\" uid=\"uid://cstkhwkpajvqu\" path=\"r"
  },
  {
    "path": "demo/addons/gut/gui/OutputText.gd",
    "chars": 9128,
    "preview": "@tool\nextends VBoxContainer\n\nvar GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')\nvar PanelControls = l"
  },
  {
    "path": "demo/addons/gut/gui/OutputText.gd.uid",
    "chars": 20,
    "preview": "uid://cax5phqs8acmu\n"
  },
  {
    "path": "demo/addons/gut/gui/OutputText.tscn",
    "chars": 4428,
    "preview": "[gd_scene load_steps=5 format=3 uid=\"uid://bqmo4dj64c7yl\"]\n\n[ext_resource type=\"Script\" uid=\"uid://cax5phqs8acmu\" path=\""
  },
  {
    "path": "demo/addons/gut/gui/ResizeHandle.gd",
    "chars": 2934,
    "preview": "@tool\nextends ColorRect\n# #############################################################################\n# Resize Handle "
  },
  {
    "path": "demo/addons/gut/gui/ResizeHandle.gd.uid",
    "chars": 20,
    "preview": "uid://duf6rfdqr6yoc\n"
  },
  {
    "path": "demo/addons/gut/gui/ResizeHandle.tscn",
    "chars": 313,
    "preview": "[gd_scene load_steps=2 format=3 uid=\"uid://bvrqqgjpyouse\"]\n\n[ext_resource type=\"Script\" uid=\"uid://duf6rfdqr6yoc\" path=\""
  },
  {
    "path": "demo/addons/gut/gui/ResultsTree.gd",
    "chars": 9106,
    "preview": "@tool\nextends Tree\n\nvar _show_orphans = true\nvar show_orphans = true :\n\tget: return _show_orphans\n\tset(val): _show_orpha"
  },
  {
    "path": "demo/addons/gut/gui/ResultsTree.gd.uid",
    "chars": 20,
    "preview": "uid://dehdhn78qv5tr\n"
  },
  {
    "path": "demo/addons/gut/gui/ResultsTree.tscn",
    "chars": 849,
    "preview": "[gd_scene load_steps=2 format=3 uid=\"uid://dls5r5f6157nq\"]\n\n[ext_resource type=\"Script\" uid=\"uid://dehdhn78qv5tr\" path=\""
  },
  {
    "path": "demo/addons/gut/gui/RunAtCursor.gd",
    "chars": 4445,
    "preview": "@tool\nextends Control\n\nvar EditorCaretContextNotifier = load('res://addons/gut/editor_caret_context_notifier.gd')\n\n@onre"
  },
  {
    "path": "demo/addons/gut/gui/RunAtCursor.gd.uid",
    "chars": 20,
    "preview": "uid://c4gmgdl1xwflw\n"
  },
  {
    "path": "demo/addons/gut/gui/RunAtCursor.tscn",
    "chars": 1884,
    "preview": "[gd_scene load_steps=3 format=3 uid=\"uid://0yunjxtaa8iw\"]\n\n[ext_resource type=\"Script\" uid=\"uid://c4gmgdl1xwflw\" path=\"r"
  },
  {
    "path": "demo/addons/gut/gui/RunExternally.gd",
    "chars": 4982,
    "preview": "@tool\nextends Control\n\n# I'm probably going to put this back in later and I don't want to create it\n# again.  Yeah, yeah"
  },
  {
    "path": "demo/addons/gut/gui/RunExternally.gd.uid",
    "chars": 20,
    "preview": "uid://bi8pg352un4om\n"
  },
  {
    "path": "demo/addons/gut/gui/RunExternally.tscn",
    "chars": 1880,
    "preview": "[gd_scene load_steps=3 format=3 uid=\"uid://cftcb0e6g7tu1\"]\n\n[ext_resource type=\"Script\" uid=\"uid://bi8pg352un4om\" path=\""
  },
  {
    "path": "demo/addons/gut/gui/RunResults.gd",
    "chars": 6068,
    "preview": "@tool\nextends Control\n\nvar GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')\n\nvar _interface = null\nvar "
  },
  {
    "path": "demo/addons/gut/gui/RunResults.gd.uid",
    "chars": 20,
    "preview": "uid://chnko3073tkcv\n"
  },
  {
    "path": "demo/addons/gut/gui/RunResults.tscn",
    "chars": 3271,
    "preview": "[gd_scene load_steps=4 format=3 uid=\"uid://4gyyn12um08h\"]\n\n[ext_resource type=\"Script\" uid=\"uid://chnko3073tkcv\" path=\"r"
  },
  {
    "path": "demo/addons/gut/gui/Settings.tscn",
    "chars": 184,
    "preview": "[gd_scene format=3 uid=\"uid://cvvvtsah38l0e\"]\n\n[node name=\"Settings\" type=\"VBoxContainer\"]\noffset_right = 388.0\noffset_b"
  },
  {
    "path": "demo/addons/gut/gui/ShellOutOptions.gd",
    "chars": 10577,
    "preview": "@tool\nextends ConfirmationDialog\n\nconst RUN_MODE_EDITOR = 'Editor'\nconst RUN_MODE_BLOCKING = 'Blocking'\nconst RUN_MODE_N"
  },
  {
    "path": "demo/addons/gut/gui/ShellOutOptions.gd.uid",
    "chars": 20,
    "preview": "uid://c64u22kybimgi\n"
  },
  {
    "path": "demo/addons/gut/gui/ShellOutOptions.tscn",
    "chars": 1020,
    "preview": "[gd_scene load_steps=2 format=3 uid=\"uid://ckv5eh8xyrwbk\"]\n\n[ext_resource type=\"Script\" uid=\"uid://c64u22kybimgi\" path=\""
  },
  {
    "path": "demo/addons/gut/gui/ShortcutButton.gd",
    "chars": 3312,
    "preview": "@tool\nextends Control\n\n\n@onready var _ctrls = {\n\tshortcut_label = $Layout/lblShortcut,\n\tset_button = $Layout/SetButton,\n"
  },
  {
    "path": "demo/addons/gut/gui/ShortcutButton.gd.uid",
    "chars": 19,
    "preview": "uid://k6hvvpekp0xw\n"
  },
  {
    "path": "demo/addons/gut/gui/ShortcutButton.tscn",
    "chars": 1681,
    "preview": "[gd_scene load_steps=2 format=3 uid=\"uid://sfb1fw8j6ufu\"]\n\n[ext_resource type=\"Script\" uid=\"uid://k6hvvpekp0xw\" path=\"re"
  },
  {
    "path": "demo/addons/gut/gui/ShortcutDialog.gd",
    "chars": 3874,
    "preview": "@tool\nextends ConfirmationDialog\n\nvar GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')\nvar default_path"
  },
  {
    "path": "demo/addons/gut/gui/ShortcutDialog.gd.uid",
    "chars": 20,
    "preview": "uid://dc5jgemxslgvl\n"
  },
  {
    "path": "demo/addons/gut/gui/ShortcutDialog.tscn",
    "chars": 6560,
    "preview": "[gd_scene load_steps=3 format=3 uid=\"uid://dj5ve0bq7xa5j\"]\n\n[ext_resource type=\"Script\" uid=\"uid://dc5jgemxslgvl\" path=\""
  },
  {
    "path": "demo/addons/gut/gui/about.gd",
    "chars": 3072,
    "preview": "@tool\nextends AcceptDialog\n\nvar GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')\n\nvar _bbcode = \\\n\"\"\"\n["
  },
  {
    "path": "demo/addons/gut/gui/about.gd.uid",
    "chars": 19,
    "preview": "uid://g7qu8ihdt3pd\n"
  },
  {
    "path": "demo/addons/gut/gui/about.tscn",
    "chars": 2141,
    "preview": "[gd_scene load_steps=5 format=3 uid=\"uid://dqbkylpsatcqm\"]\n\n[ext_resource type=\"Script\" uid=\"uid://g7qu8ihdt3pd\" path=\"r"
  },
  {
    "path": "demo/addons/gut/gui/editor_globals.gd",
    "chars": 2485,
    "preview": "@tool\n\nstatic var GutUserPreferences = load(\"res://addons/gut/gui/gut_user_preferences.gd\")\nstatic var temp_directory = "
  },
  {
    "path": "demo/addons/gut/gui/editor_globals.gd.uid",
    "chars": 20,
    "preview": "uid://cbi00ubn046c2\n"
  },
  {
    "path": "demo/addons/gut/gui/gut_config_gui.gd",
    "chars": 10800,
    "preview": "var PanelControls = load(\"res://addons/gut/gui/panel_controls.gd\")\nvar GutConfig = load('res://addons/gut/gut_config.gd'"
  },
  {
    "path": "demo/addons/gut/gui/gut_config_gui.gd.uid",
    "chars": 20,
    "preview": "uid://chosc1tvfaduq\n"
  },
  {
    "path": "demo/addons/gut/gui/gut_gui.gd",
    "chars": 5954,
    "preview": "extends Control\n# ##############################################################################\n# This is the decoupled"
  },
  {
    "path": "demo/addons/gut/gui/gut_gui.gd.uid",
    "chars": 20,
    "preview": "uid://blvhsbnsvfyow\n"
  },
  {
    "path": "demo/addons/gut/gui/gut_logo.gd",
    "chars": 6090,
    "preview": "@tool\nextends Node2D\n\nclass Eyeball:\n\textends Node2D\n\n\tvar _should_draw_laser = false\n\tvar _laser_end_pos = Vector2.ZERO"
  },
  {
    "path": "demo/addons/gut/gui/gut_logo.gd.uid",
    "chars": 20,
    "preview": "uid://b8lvgepb64m8t\n"
  },
  {
    "path": "demo/addons/gut/gui/gut_user_preferences.gd",
    "chars": 2327,
    "preview": "class GutEditorPref:\n\tvar gut_pref_prefix = 'gut/'\n\tvar pname = '__not_set__'\n\tvar default = null\n\tvar value = '__not_se"
  },
  {
    "path": "demo/addons/gut/gui/gut_user_preferences.gd.uid",
    "chars": 20,
    "preview": "uid://dsndkn6whyiov\n"
  },
  {
    "path": "demo/addons/gut/gui/option_maker.gd",
    "chars": 3078,
    "preview": "var PanelControls = load(\"res://addons/gut/gui/panel_controls.gd\")\n\n# All titles so we can free them when we want.\nvar _"
  },
  {
    "path": "demo/addons/gut/gui/option_maker.gd.uid",
    "chars": 20,
    "preview": "uid://bjahqsqo645sf\n"
  },
  {
    "path": "demo/addons/gut/gui/panel_controls.gd",
    "chars": 12389,
    "preview": "# ------------------------------------------------------------------------------\n# -------------------------------------"
  },
  {
    "path": "demo/addons/gut/gui/panel_controls.gd.uid",
    "chars": 20,
    "preview": "uid://db54jy04d8w7p\n"
  },
  {
    "path": "demo/addons/gut/gui/run_from_editor.gd",
    "chars": 640,
    "preview": "# ------------------------------------------------------------------------------\n# This is the entry point when running "
  },
  {
    "path": "demo/addons/gut/gui/run_from_editor.gd.uid",
    "chars": 20,
    "preview": "uid://bwf2iuidqfkpl\n"
  },
  {
    "path": "demo/addons/gut/gui/run_from_editor.tscn",
    "chars": 250,
    "preview": "[gd_scene load_steps=2 format=3 uid=\"uid://bgj3fm5d8yvjw\"]\n\n[ext_resource type=\"Script\" uid=\"uid://bwf2iuidqfkpl\" path=\""
  },
  {
    "path": "demo/addons/gut/gut.gd",
    "chars": 46322,
    "preview": "extends 'res://addons/gut/gut_to_move.gd'\nclass_name GutMain\n## The GUT brains.\n##\n## Most of this class is for internal"
  },
  {
    "path": "demo/addons/gut/gut.gd.uid",
    "chars": 20,
    "preview": "uid://duvvxvj18c04d\n"
  },
  {
    "path": "demo/addons/gut/gut_cmdln.gd",
    "chars": 2564,
    "preview": "# ------------------------------------------------------------------------------\n# Description\n# -----------\n# Entry poi"
  },
  {
    "path": "demo/addons/gut/gut_cmdln.gd.uid",
    "chars": 20,
    "preview": "uid://bxw30gwbwnh55\n"
  }
]

// ... and 360 more files (download for full content)

About this extraction

This page contains the full source code of the utopia-rise/fmod-gdnative GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 560 files (21.7 MB), approximately 323.4k tokens, and a symbol index with 126 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!