Skip to content

Instantly share code, notes, and snippets.

@Andre-LA
Last active December 13, 2025 03:54
Show Gist options
  • Select an option

  • Save Andre-LA/800b39c74cb5c83bf640f0776e9c4b40 to your computer and use it in GitHub Desktop.

Select an option

Save Andre-LA/800b39c74cb5c83bf640f0776e9c4b40 to your computer and use it in GitHub Desktop.
Python script to dump teal symbols. Note this is a fork of o3de's dump_lua_symbols.py
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
# NOTE: (the instructions below is for dump_lua_symbols.py, just use pyRunFile with dump_teal_symbols.py)
# The easiest way to run this script in O3DE
# is to run it via the "Python Scripts" window in the Editor:
# Tools -> Other -> Python Scripts.
# Will produce the file <game_project>\lua_symbols.txt
#
# Alternatively from the Editor console:
# pyRunFile C:\GIT\o3de\Gems\EditorPythonBindings\Editor\Scripts\dump_lua_symbols.py
# Will produce the file <game_project>\lua_symbols.txt
#
# or if you need to customize the name of the output file
# pyRunFile C:\GIT\o3de\Gems\EditorPythonBindings\Editor\Scripts\dump_lua_symbols.py -o my_lua_name.txt
# Will produce the file <game_project>\my_lua_name.txt
# This script shows basic usage of the LuaSymbolsReporterBus,
# Which can be used to report all symbols available for
# game scripting with Lua.
import sys
import os
import argparse
import re
from typing import TextIO
import azlmbr.bus as azbus
import azlmbr.script as azscript
import azlmbr.legacy.general as azgeneral
re_return_type = re.compile("^\[\=([\w_\.]+)\]")
re_return_and_args = re.compile("^(?:\[\=([\w_.]+)\] )?([\w_, .]+)")
re_args = re.compile("([\w_.]+)[, ]?")
re_args_checker = re.compile("(([\w_.]+, )+([\w_.]+)?)|[\w_.]+")
re_symbol_checker = re.compile("[\w_]+")
arg_separator = ", "
types_map = {
"any": "any",
"void": "any",
"...": "any...",
"char": "string",
"bool": "boolean",
"float": "number",
"double": "number",
"int": "integer",
"short": "integer",
"long": "integer",
"unsignedchar": "integer",
"unsignedint": "integer",
"unsignedlong": "integer",
"unsignedshort": "integer",
}
unknown_types = []
known_types = []
start_content = """
global interface LuaComponent
entityId: EntityId
OnActivate: function(self)
OnDeactivate: function(self)
end
global interface EBusHandler<T>
Disconnect: function(self)
end
local interface BusThatHasAHandler<T> -- TODO: think of better name
Connect: function(table, ...: any): EBusHandler<T>
end
"""
# TODO: I don't like manual work, but for now, let's use it
# later the C++ bit probably could help us here...
metamethods_map: dict[str, list[str]] = {
"Vector3": [
"__call: function(self, number): Vector3",
"__call: function(self, number, number, number): Vector3",
"__mul: function(Vector3, Vector3): Vector3",
"__mul: function(Vector3, number): Vector3",
]
}
# TODO: stop localizing fields
# TODO: use list[type], and try to type everything
def to_teal_type(t: str):
x = types_map.get(t)
if x != None:
return x
if t not in unknown_types:
unknown_types.append(t)
return t
def ebus_has_broadcast(ebus_symbol:azlmbr.script.LuaEBusSymbol) -> bool:
return ebus_symbol.canBroadcast
def ebus_has_events(ebus_symbol:azlmbr.script.LuaEBusSymbol) -> bool:
for sender in ebus_symbol.senders:
if sender.category == "Event":
return True
return False
def ebus_has_notifications(ebus_symbol:azlmbr.script.LuaEBusSymbol) -> bool:
for sender in ebus_symbol.senders:
if sender.category == "Notification":
return True
return False
def _dump_teal_property(result, prop_sym, prefix: str):
result.append(f"{prefix}{prop_sym.name}: any\n")
def _dump_teal_args(result, args_info: str, try_find_self_arg: bool):
return_and_args_match = re_return_and_args.match(args_info)
if return_and_args_match == None:
return
args_content = return_and_args_match.group(2)
has_args = re_args_checker.fullmatch(args_content)
if has_args == None:
return
first_arg_is_self: bool = False
args_array = []
for arg in re_args.finditer(args_content):
args_array.append(arg.group(1))
if try_find_self_arg and len(args_array) >= 2:
if args_array[0] == "void" and args_array[1] == "void":
first_arg_is_self = True
if first_arg_is_self:
args_array.pop(0)
args_array[0] = "self"
args_array = map(to_teal_type, args_array)
args_result = arg_separator.join(args_array)
result.append(args_result)
def _dump_teal_function(result, fun_sym, prefix: str):
return_type_match = re_return_type.match(fun_sym.debugArgumentInfo)
return_type = "any"
if return_type_match != None:
return_type = return_type_match.group(1)
result.append(f"{prefix}{fun_sym.name}: function(")
_dump_teal_args(result, fun_sym.debugArgumentInfo, False)
result.append(f"): {to_teal_type(return_type)}\n")
def _dump_teal_class_symbol(result, class_symbol: azlmbr.script.LuaClassSymbol):
has_valid_class_name = re_symbol_checker.fullmatch(class_symbol.name)
if has_valid_class_name == None:
return
if class_symbol.name not in known_types:
known_types.append(class_symbol.name)
result.append(f"global record {class_symbol.name}\n")
# TODO: sort properties
for property_symbol in class_symbol.properties:
_dump_teal_property(result, property_symbol, "\t")
if len(class_symbol.properties) > 0:
result.append("\n")
# TODO: sort method
for method_symbol in class_symbol.methods:
_dump_teal_function(result, method_symbol, "\t")
metamethods = metamethods_map.get(class_symbol.name)
if metamethods != None:
result.append("\n")
for metamethod in metamethods:
result.append(f"\tmetamethod {metamethod}\n")
result.append("end\n")
def _dump_teal_classes(result):
class_symbols = azscript.LuaSymbolsReporterBus(
azbus.Broadcast, "GetListOfClasses"
)
result.append("--[[ ======== Classes ========== ]]--\n")
sorted_classes_by_named = sorted(class_symbols, key=lambda class_symbol: class_symbol.name)
for class_symbol in sorted_classes_by_named:
_dump_teal_class_symbol(result, class_symbol)
result.append("\n\n")
def _dump_teal_globals(result):
# dump global properties
global_properties = azscript.LuaSymbolsReporterBus(
azbus.Broadcast, "GetListOfGlobalProperties"
)
result.append("--[[ ======== Global Properties ========== ]]--\n")
sorted_properties_by_name = sorted(global_properties, key = lambda symbol: symbol.name)
for property_symbol in sorted_properties_by_name:
_dump_teal_property(result, property_symbol, "global ")
result.append("\n\n")
# dump global functions
global_functions = azscript.LuaSymbolsReporterBus(
azbus.Broadcast, "GetListOfGlobalFunctions"
)
result.append("--[[ ======== Global Functions ========== ]]--\n")
sorted_functions_by_name = sorted(global_functions, key=lambda symbol: symbol.name)
for function_symbol in sorted_functions_by_name:
_dump_teal_function(result, function_symbol, "global ")
result.append("\n\n")
def _dump_teal_ebus_sender(result, ebus_sender: azlmbr.script.LuaEBusSender, prefix: str):
result.append(f"{prefix}{ebus_sender.name}: function(")
_dump_teal_args(result, ebus_sender.debugArgumentInfo, True)
result.append("): any\n")
def _dump_teal_ebus_senders(result, ebus_senders, category: str, prefix: str):
for sender in ebus_senders:
if sender.category == category:
_dump_teal_ebus_sender(result, sender, prefix)
def _dump_teal_ebus(result, ebus_symbol: azlmbr.script.LuaEBusSymbol):
has_valid_class_name = re_symbol_checker.fullmatch(ebus_symbol.name)
if has_valid_class_name == None:
return
sorted_senders = sorted(ebus_symbol.senders, key=lambda symbol: symbol.name)
result.append(f"global record {ebus_symbol.name}\n")
if ebus_symbol.hasHandler:
result.append(f"\tis BusThatHasAHandler<{ebus_symbol.name}>\n\n")
if ebus_has_events(ebus_symbol):
result.append("\trecord Event\n")
_dump_teal_ebus_senders(result, sorted_senders, "Event", "\t\t")
result.append("\tend\n\n")
if ebus_has_broadcast(ebus_symbol):
result.append("\trecord Broadcast\n")
_dump_teal_ebus_senders(result, sorted_senders, "Broadcast", "\t\t")
result.append("\tend\n")
if ebus_has_notifications(ebus_symbol):
result.append("\tinterface Notification\n")
_dump_teal_ebus_senders(result, sorted_senders, "Notification", "\t\t")
result.append("\tend\n")
result.append("end\n")
result.append("\n\n")
def _dump_teal_ebuses(result):
ebuses = azscript.LuaSymbolsReporterBus(
azbus.Broadcast, "GetListOfEBuses"
)
result.append("--[[ ======== Ebus List ========== ]]\n")
sorted_ebuses_by_name = sorted(ebuses, key=lambda symbol: symbol.name)
for ebus_symbol in sorted_ebuses_by_name:
_dump_teal_ebus(result, ebus_symbol)
result.append("\n\n")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Dumps All ebuses, classes and global symbols available for Lua scripting.')
parser.add_argument('--outfile', '--o', default='o3de.d.tl',
help='output file file where all the symbols will be dumped to. If relative, will be under the game project folder.')
parser.add_argument('--all', '--a', default=True, action='store_true',
help='If true dumps all symbols to the outfile. Equivalent to specifying --c --g --e')
parser.add_argument('--classes', '--c', default=False, action='store_true',
help='If true dumps Class symbols.')
parser.add_argument('--globals', '--g', default=False, action='store_true',
help='If true dumps Global symbols.')
parser.add_argument('--ebuses', '--e', default=False, action='store_true',
help='If true dumps Ebus symbols.')
args = parser.parse_args()
output_file_name = args.outfile
if not os.path.isabs(output_file_name):
game_root_path = os.path.normpath(azgeneral.get_game_folder())
output_file_name = os.path.join(game_root_path, output_file_name)
try:
file_obj = open(output_file_name, 'wt')
except Exception as e:
print(f"Failed to open {output_file_name}: {e}")
sys.exit(-1)
result = []
if args.classes:
_dump_teal_classes(result)
if args.globals:
_dump_teal_globals(result)
if args.ebuses:
_dump_teal_ebuses(result)
if (not args.classes) and (not args.globals) and (not args.ebuses):
_dump_teal_classes(result)
_dump_teal_globals(result)
_dump_teal_ebuses(result)
file_obj.write(start_content)
file_obj.write("\n\n")
for known_type in known_types:
if known_type in unknown_types:
unknown_types.remove(known_type)
for unknown_type in unknown_types:
file_obj.write(f"global record {unknown_type} end\n")
file_obj.write("\n\n")
for result_line in result:
file_obj.write(result_line)
file_obj.close()
print(f" Teal Symbols Are available in: {output_file_name}")
@Andre-LA
Copy link
Author

Andre-LA commented Oct 26, 2025

How to use it:

  1. Install teal and cyan, you'll be using cyan for convenience.
  2. Create two directories on Assets folder (or other place you prefer): Teal and Lua
  3. Create a tlconfig.lua file with the contents below:
return {
	gen_target = "5.4", -- o3de uses 5.4
	gen_compat = "off", -- no need for compatibility mode
	source_dir = "Assets/Teal", -- adjust if needed
	build_dir = "Assets/Lua", -- same
	global_env_def = 'o3de', -- refers to o3de.d.tl
}
  1. Generate o3de.d.tl file, for that you run the script shared in this gist.
    a. To run that script, save the python file on your project, then go to O3DE Editor, go to Console tool, then run the command below:
pyRunFile /full/path/to/dump_teal_symbols.py
  1. Every time you create/modify/delete a script event, re-run the python file
  2. Every time you create/modify/delete a teal file, use cyan build --prune command to (re-)generate the lua files.

@Andre-LA
Copy link
Author

Andre-LA commented Oct 31, 2025

Updated, now we can do things like this:

local record MyComponent
	-- LuaComponent has OnActivate, entityId, etc (WIP)
	is LuaComponent, TickBus.Notification -- every Bus with Notifications has a Notification interface, with the notifications callbacks inside it.


	record PropertiesType
		Speed: number
		Direction: Vector3
	end

	Properties: PropertiesType

	-- handler of a specific Bus, thus a typed handler
	tickHandler: EBusHandler<TickBus>
end

local NewComponent: MyComponent = 
{
	Properties =
	{
		-- Property definitions
		Speed = 10,
		Direction = Vector3.CreateAxisZ(1)
	}
}

-- OnActivate works because our component "is" a "LuaComponent"
function NewComponent:OnActivate()
	-- TickBus is a "BusThatHasAHandler"... yeah I need to think of a better name :)
	self.tickHandler = TickBus.Connect(self as table) -- returns EBusHandler<TickBus>!
end

function NewComponent:OnDeactivate()
	self.tickHandler:Disconnect()
end

-- Since our component "is" also a "TickBus.Notification", teal will understand
-- that it has a OnTick callback.
function NewComponent:OnTick(dt: number, time: ScriptTimePoint): any -- this `: any` is a current limitation, every notification for now returns an any

	local delta = Vector3(0) -- __call isn't automatic unfortately, check metamethods_map
	delta = self.Properties.Direction * self.Properties.Speed -- same
	TransformBus.Event.MoveEntity(self.entityId, delta)
end

return NewComponent

@Andre-LA
Copy link
Author

Andre-LA commented Dec 13, 2025

New version, needs build from my teal-gen branch:

experimental/teal_gen

#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#

# NOTE: (the instructions below is for dump_lua_symbols.py, just use pyRunFile with dump_teal_symbols.py)

# The easiest way to run this script in O3DE
# is to run it via the "Python Scripts" window in the Editor:
# Tools -> Other -> Python Scripts.
# Will produce the file <game_project>\lua_symbols.txt
#
# Alternatively from the Editor console:
# pyRunFile C:\GIT\o3de\Gems\EditorPythonBindings\Editor\Scripts\dump_lua_symbols.py
# Will produce the file <game_project>\lua_symbols.txt
#
# or if you need to customize the name of the output file
# pyRunFile C:\GIT\o3de\Gems\EditorPythonBindings\Editor\Scripts\dump_lua_symbols.py -o my_lua_name.txt
# Will produce the file <game_project>\my_lua_name.txt

# This script shows basic usage of the LuaSymbolsReporterBus,
# Which can be used to report all symbols available for
# game scripting with Lua.

import sys
import os
import argparse
import re
from typing import TextIO

# import class_def_extraction

import azlmbr.bus as azbus
import azlmbr.script as azscript
import azlmbr.legacy.general as azgeneral

re_return_type = re.compile("^\[\=([\w\.:]+)\]")
re_return_and_args = re.compile("^(?:\[\=([\w.:]+)\] )?([\w, :.]+)")
re_fn_info = re.compile(" -- (.*)")

re_args = re.compile("([\w.]+): ([\w.:]+)(?:, )?|([\w.:]+)(?:, )?")

re_args_checker = re.compile("(([\w ]+: )?([\w<>: ]+)(?:, )?)+")
re_symbol_checker = re.compile("[\w:]+")

arg_separator = ", "

types_map = {
    "any": "any",
    "void": "any",
    "...": "any...",

    "char": "string",
    "bool": "boolean",

    "float": "number",
    "double": "number",

    "int": "integer",
    "short": "integer",
    "long": "integer",

    "unsignedchar": "integer",
    "unsignedint": "integer",
    "unsignedlong": "integer",
    "unsignedshort": "integer",
}

all_types: list[str] = []
unknown_types: list[str] = []
known_types: list[str] = []

start_content = """
global interface LuaComponent
	entityId: EntityId

	OnActivate: function(self)
	OnDeactivate: function(self)
end

global interface EBusHandler<T>
	Disconnect: function(self)
end

local interface BusThatHasAHandler<T> -- TODO: think of better name
	Connect: function(table, ...: any): EBusHandler<T>
end
"""

# TODO: I don't like manual work, but for now, let's use it
#       later the C++ bit probably could help us here...
metamethods_map: dict[str, list[str]] = {
	"Vector3": [
		"__call: function(self, number, number, number): Vector3",
		"__mul: function(Vector3, number): Vector3",
	]
}

# vector3_classdef: class_def_extraction.ClassDef = class_def_extraction.class_def_from_file("/run/media/dreunix/Arquivos/o3de_things/api.o3de.org/frameworks/doxygen-xml/class_a_z_1_1_vector3.xml")

def to_teal_type(t: str) -> str:
    x = types_map.get(t)
    if x != None:
        return x
    if t not in unknown_types:
        unknown_types.append(t)
    return t

def ebus_has_broadcast(ebus_symbol: azlmbr.script.LuaEBusSymbol) -> bool:
    return ebus_symbol.canBroadcast

def ebus_has_events(ebus_symbol: azlmbr.script.LuaEBusSymbol) -> bool:
    for sender in ebus_symbol.senders:
        if sender.category == "Event":
            return True
    return False

def ebus_has_notifications(ebus_symbol: azlmbr.script.LuaEBusSymbol) -> bool:
    for sender in ebus_symbol.senders:
        if sender.category == "Notification":
            return True
    return False

def _dump_teal_property(result: list[str], prop_sym: azlmbr.script.LuaPropertySymbol, prefix: str):
    result.append(f"{prefix}{prop_sym.name}: any\n")

def _dump_teal_args(result: list[str], args_info: str, try_find_self_arg: bool):
    # print(f"dumping args: {args_info}")
    return_and_args_match = re_return_and_args.match(args_info)

    if return_and_args_match == None:
        # print("return and args match failed")
        return

    args_content = return_and_args_match.group(2)
    # print(f"args_content is: {args_content}")
    has_args = re_args_checker.fullmatch(args_content)

    if has_args == None:
        # print("has args is None")
        return

    first_arg_is_self: bool = False
    args_array: list[str] = []
    # print("actually dumping args...")

    for arg in re_args.finditer(args_content):
        # Foo: Bar
        argName = arg.group(1)
        argType = arg.group(2)

        # Bar
        if argType == None:
            argType = arg.group(3)

        # for g in arg.groups():
        #     print(f"test: {g}")

        if argType != None:
            argType = argType.replace(":", "_")
            argType = argType.replace("<", "_")
            argType = argType.replace(">", "_")

        if argName != None and argType != None:
            args_array.append(f"{argName}: {to_teal_type(argType)}")
        elif argName != None:
            args_array.append(f"{argName}: any")
        elif argType != None:
            args_array.append(f"{to_teal_type(argType)}")

    # print(f"args collected! len: {len(args_array)}")

    if try_find_self_arg and len(args_array) >= 2:
        if args_array[0] == "any" and args_array[1] == "any":
            first_arg_is_self = True

    if first_arg_is_self:
        args_array.pop(0)
        args_array[0] = "self"

    # print('args array')
    # for a in args_array:
    #     print(f"arg: {a}")

    args_result: str = arg_separator.join(args_array)

    result.append(args_result)

def _dump_teal_function(result: list[str], fun_sym: azlmbr.script.LuaMethodSymbol, prefix: str): #, api_def: class_def_extraction.ApiDef | None):
    # print(f"dumping function: {fun_sym.name} --> {fun_sym.debugArgumentInfo}")

    return_type_match = re_return_type.match(fun_sym.debugArgumentInfo)
    return_type = "any"

    if return_type_match != None:
        return_type = return_type_match.group(1)
        # print("return type match worked: {return_type}")

    has_info = re_fn_info.match(fun_sym.debugArgumentInfo)

    if has_info != None:
        result.append(f"--- {has_info.group(1)}\n")

    result.append(f"{prefix}{fun_sym.name}: function(")

    # this breaks the script and it seems it has no arguments anyway
    if fun_sym.name != "AcquireOwnership" and fun_sym.name != "ReleaseOwnership":
        _dump_teal_args(result, fun_sym.debugArgumentInfo, False)

    result.append(f"): {to_teal_type(return_type)}\n")

def _dump_teal_class_symbol(result: list[str], class_symbol: azlmbr.script.LuaClassSymbol):
    has_valid_class_name = re_symbol_checker.fullmatch(class_symbol.name)

    if has_valid_class_name == None:
        return

    if class_symbol.name in all_types:
        return # avoids duplicated types

    if class_symbol.name not in known_types:
        known_types.append(class_symbol.name)

    # print(f"class symbol: {class_symbol.name}")
    result.append(f"global record {class_symbol.name}\n")
    all_types.append(class_symbol.name)

    sorted_properties = sorted(class_symbol.properties, key = lambda property: property.name)

    for property_symbol in sorted_properties:
        _dump_teal_property(result, property_symbol, "\t")

    if len(sorted_properties) > 0:
        result.append("\n")

    sorted_methods = sorted(class_symbol.methods, key = lambda method: method.name)
    for method_symbol in sorted_methods:
        _dump_teal_function(result, method_symbol, "\t")

    metamethods = metamethods_map.get(class_symbol.name)
    if metamethods != None:
        result.append("\n")
        for metamethod in metamethods:
            result.append(f"\tmetamethod {metamethod}\n")

    result.append("end\n")

def _dump_teal_classes(result: list[str]):
    class_symbols = azscript.LuaSymbolsReporterBus(
        azbus.Broadcast, "GetListOfClasses"
    )
    result.append("--[[ ========  Classes ========== ]]--\n")
    sorted_classes_by_named = sorted(class_symbols, key=lambda class_symbol: class_symbol.name)
    for class_symbol in sorted_classes_by_named:
        _dump_teal_class_symbol(result, class_symbol)
        result.append("\n\n")

def _dump_teal_globals(result: list[str]):
    # dump global properties
    global_properties = azscript.LuaSymbolsReporterBus(
        azbus.Broadcast, "GetListOfGlobalProperties"
    )

    result.append("--[[ ========  Global Properties ========== ]]--\n")

    sorted_properties_by_name = sorted(global_properties, key = lambda symbol: symbol.name)

    for property_symbol in sorted_properties_by_name:
        _dump_teal_property(result, property_symbol, "global ")

    result.append("\n\n")

    # dump global functions

    global_functions = azscript.LuaSymbolsReporterBus(
        azbus.Broadcast, "GetListOfGlobalFunctions"
    )

    result.append("--[[ ========  Global Functions ========== ]]--\n")

    sorted_functions_by_name = sorted(global_functions, key=lambda symbol: symbol.name)

    for function_symbol in sorted_functions_by_name:
        _dump_teal_function(result, function_symbol, "global ")

    result.append("\n\n")

def _dump_teal_ebus_sender(result: list[str], ebus_sender: azlmbr.script.LuaEBusSender, prefix: str):
    # print(f"ebus sender: {ebus_sender.name}")
    result.append(f"{prefix}{ebus_sender.name}: function(")
    _dump_teal_args(result, ebus_sender.debugArgumentInfo, True)
    result.append("): any\n")

def _dump_teal_ebus_senders(result: list[str], ebus_senders: list[azlmbr.script.LuaEBusSender], category: str, prefix: str):
    for sender in ebus_senders:
        if sender.category == category:
            # print(f"sender : {sender.name}")
            _dump_teal_ebus_sender(result, sender, prefix)

def _dump_teal_ebus(result: list[str], ebus_symbol: azlmbr.script.LuaEBusSymbol):
    has_valid_class_name = re_symbol_checker.fullmatch(ebus_symbol.name)

    if has_valid_class_name == None:
        return

    if ebus_symbol.name in all_types:
        return # avoids duplicated types

    sorted_senders = sorted(ebus_symbol.senders, key=lambda symbol: symbol.name)

    result.append(f"global record {ebus_symbol.name}\n")
    all_types.append(ebus_symbol.name)

    if ebus_symbol.hasHandler:
        result.append(f"\tis BusThatHasAHandler<{ebus_symbol.name}>\n\n")

    if ebus_has_events(ebus_symbol):
        result.append("\trecord Event\n")
        _dump_teal_ebus_senders(result, sorted_senders, "Event", "\t\t")
        result.append("\tend\n\n")

    if ebus_has_broadcast(ebus_symbol):
        result.append("\trecord Broadcast\n")
        _dump_teal_ebus_senders(result, sorted_senders, "Broadcast", "\t\t")
        result.append("\tend\n")

    if ebus_has_notifications(ebus_symbol):
        result.append("\tinterface Notification\n")
        # print(f"notifications of {ebus_symbol.name}")
        _dump_teal_ebus_senders(result, sorted_senders, "Notification", "\t\t")
        result.append("\tend\n")

    result.append("end\n")
    result.append("\n\n")


def _dump_teal_ebuses(result: list[str]):
    ebuses = azscript.LuaSymbolsReporterBus(
        azbus.Broadcast, "GetListOfEBuses"
    )

    result.append("--[[ ========  Ebus List ========== ]]\n")

    sorted_ebuses_by_name = sorted(ebuses, key=lambda symbol: symbol.name)
    for ebus_symbol in sorted_ebuses_by_name:
        _dump_teal_ebus(result, ebus_symbol)

    result.append("\n\n")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Dumps All ebuses, classes and global symbols available for Lua scripting.')
    parser.add_argument('--outfile', '--o', default='o3de.d.tl',
                    help='output file file where all the symbols will be dumped to. If relative, will be under the game project folder.')
    parser.add_argument('--all', '--a', default=True, action='store_true',
                    help='If true dumps all symbols to the outfile. Equivalent to specifying --c --g --e')
    parser.add_argument('--classes', '--c', default=False, action='store_true',
                    help='If true dumps Class symbols.')
    parser.add_argument('--globals', '--g', default=False, action='store_true',
                    help='If true dumps Global symbols.')
    parser.add_argument('--ebuses', '--e', default=False, action='store_true',
                    help='If true dumps Ebus symbols.')

    args = parser.parse_args()
    output_file_name = args.outfile
    if not os.path.isabs(output_file_name):
        game_root_path = os.path.normpath(azgeneral.get_game_folder())
        output_file_name = os.path.join(game_root_path, output_file_name)
    try:
        file_obj = open(output_file_name, 'wt')
    except Exception as e:
        # print(f"Failed to open {output_file_name}: {e}")
        sys.exit(-1)

    result : list[str] = []

    if args.classes:
        _dump_teal_classes(result)

    if args.globals:
        _dump_teal_globals(result)

    if args.ebuses:
        _dump_teal_ebuses(result)

    if (not args.classes) and (not args.globals) and (not args.ebuses):
        _dump_teal_classes(result)
        _dump_teal_globals(result)
        _dump_teal_ebuses(result)

    file_obj.write(start_content)
    file_obj.write("\n\n")

    for known_type in known_types:
        if known_type in unknown_types:
            unknown_types.remove(known_type)

    for unknown_type in unknown_types:
      file_obj.write(f"global record {unknown_type} end\n")

    file_obj.write("\n\n")

    for result_line in result:
        file_obj.write(result_line)

    file_obj.close()
    # print(f" Teal Symbols Are available in: {output_file_name}")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment