mirror of
https://github.com/HarbourMasters/Starship.git
synced 2025-04-28 20:37:58 +03:00
Added documentation to the example
This commit is contained in:
parent
40eea8705f
commit
01723fd67a
5 changed files with 27708 additions and 4 deletions
27247
example/.vscode/api_definitions.lua
vendored
Normal file
27247
example/.vscode/api_definitions.lua
vendored
Normal file
File diff suppressed because it is too large
Load diff
6
example/.vscode/settings.json
vendored
Normal file
6
example/.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"Lua.workspace.library": [
|
||||||
|
".vscode/api_definitions.lua"
|
||||||
|
],
|
||||||
|
"Lua.diagnostics.disable": ["undefined-global", "undefined-symbol"]
|
||||||
|
}
|
|
@ -2,12 +2,12 @@ require("test.lua")
|
||||||
|
|
||||||
function OnPlayUpdate(ev)
|
function OnPlayUpdate(ev)
|
||||||
PrintTest()
|
PrintTest()
|
||||||
if((Game.gInputPress().button & N64Buttons.BTN_L) != 0) then
|
if((Game.gInputPress().button & N64Buttons.BTN_L) ~= 0) then
|
||||||
local reticlePos = Game.D_display_801613E0(0)
|
local reticlePos = Game.D_display_801613E0(0)
|
||||||
local actorId = math.random(176, 291)
|
local actorId = math.random(176, 291)
|
||||||
local actor = Game_SpawnActor(actorId);
|
local actor = Game_SpawnActor(actorId);
|
||||||
|
|
||||||
if (actor != nil) then
|
if (actor ~= nil) then
|
||||||
actor.obj.pos.x = reticlePos.x * 1.7
|
actor.obj.pos.x = reticlePos.x * 1.7
|
||||||
actor.obj.pos.y = 200.0
|
actor.obj.pos.y = 200.0
|
||||||
actor.obj.pos.z = Game.gPlayer().pos.z - 1500.0 - (reticlePos.y * 1.7)
|
actor.obj.pos.z = Game.gPlayer().pos.z - 1500.0 - (reticlePos.y * 1.7)
|
||||||
|
|
|
@ -103,8 +103,8 @@ namespace UIWidgets {
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Sizes {
|
namespace Sizes {
|
||||||
const ImVec2 Inline = ImVec2(0.0f, 0.0f);
|
const ImVec2 Inline = ImVec2(0.0f, 0.0f); // sol:ignore
|
||||||
const ImVec2 Fill = ImVec2(-1.0f, 0.0f);
|
const ImVec2 Fill = ImVec2(-1.0f, 0.0f); // sol:ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
enum LabelPosition {
|
enum LabelPosition {
|
||||||
|
|
451
tools/def2lua.py
Normal file
451
tools/def2lua.py
Normal file
|
@ -0,0 +1,451 @@
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
|
||||||
|
blacklist = [
|
||||||
|
'audio',
|
||||||
|
'portable-file-dialogs.h',
|
||||||
|
'rmonint.h',
|
||||||
|
'PR/',
|
||||||
|
'libultra/',
|
||||||
|
'libc/',
|
||||||
|
'dbgproto',
|
||||||
|
'prevent',
|
||||||
|
'piint',
|
||||||
|
'siint',
|
||||||
|
'sf64dma',
|
||||||
|
'osint',
|
||||||
|
'FrameInterpolation',
|
||||||
|
'mods.h'
|
||||||
|
]
|
||||||
|
|
||||||
|
event_list = []
|
||||||
|
|
||||||
|
def parse_enums(header, as_value=False):
|
||||||
|
try:
|
||||||
|
with open(header, 'r') as file:
|
||||||
|
lines = file.readlines()
|
||||||
|
except IOError:
|
||||||
|
raise RuntimeError("Failed to open header files for enums node in config")
|
||||||
|
|
||||||
|
# Regex pattern to match enum declarations
|
||||||
|
enum_regex = re.compile(r"enum\s+(\w+)\s*(?:\s*:\s*(\w+))?[\s\n\r]*\{")
|
||||||
|
|
||||||
|
in_enum = False
|
||||||
|
enum_index = None
|
||||||
|
enum_name = ""
|
||||||
|
enum = {}
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
line = line.strip()
|
||||||
|
|
||||||
|
if not in_enum:
|
||||||
|
# Check if the line matches the enum declaration pattern
|
||||||
|
match = enum_regex.search(line)
|
||||||
|
if match and len(match.groups()) > 1:
|
||||||
|
enum_name = match.group(1)
|
||||||
|
enum[enum_name] = []
|
||||||
|
in_enum = True
|
||||||
|
enum_index = -1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if '}' in line:
|
||||||
|
in_enum = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Remove any comments and non-alphanumeric characters
|
||||||
|
line = re.sub(r'(/\*.*?\*/)|(//.*$)|([^a-zA-Z0-9=_\-\.])', '', line)
|
||||||
|
|
||||||
|
if len(line) == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if '=' in line:
|
||||||
|
# Extract the value after the '=' sign
|
||||||
|
value = line.split('=')[1].strip()
|
||||||
|
# Extract the name before the '=' sign
|
||||||
|
name = line.split('=')[0].strip()
|
||||||
|
enum_index = int(value, 0) # Convert the value to an integer with base 0 (detects hex, oct, etc.)
|
||||||
|
enum[enum_name].append({
|
||||||
|
'name': name,
|
||||||
|
'value': enum_index
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
# Increment the enum index if no '=' is found
|
||||||
|
enum_index += 1
|
||||||
|
enum[enum_name].append({
|
||||||
|
'name': line,
|
||||||
|
'value': enum_index
|
||||||
|
})
|
||||||
|
|
||||||
|
for enum_name, values in enum.items():
|
||||||
|
print(f'---@enum {enum_name}')
|
||||||
|
print(f'{enum_name} = {{')
|
||||||
|
for i, entry in enumerate(values):
|
||||||
|
key = entry['name']
|
||||||
|
value = entry['value']
|
||||||
|
if 'ifdef' in key or 'endif' in entry['name'] or 'else' in key:
|
||||||
|
continue
|
||||||
|
key_name = key
|
||||||
|
key_name = key_name.replace('EVENT_PRIORITY_', '')
|
||||||
|
key_name = key_name.replace('SF64_VER_', '')
|
||||||
|
print(f' {key_name} = {value}{"," if i < len(values) - 1 else ""}')
|
||||||
|
print('}')
|
||||||
|
print('')
|
||||||
|
|
||||||
|
def sanitize_type(member_type):
|
||||||
|
member_type = member_type.strip()
|
||||||
|
if len(member_type) == 0:
|
||||||
|
return 'any'
|
||||||
|
member_type = member_type.replace('uint8_t', 'number')
|
||||||
|
member_type = member_type.replace('uint16_t', 'number')
|
||||||
|
member_type = member_type.replace('uint32_t', 'number')
|
||||||
|
member_type = member_type.replace('uint64_t', 'number')
|
||||||
|
member_type = member_type.replace('int8_t', 'number')
|
||||||
|
member_type = member_type.replace('int16_t', 'number')
|
||||||
|
member_type = member_type.replace('int32_t', 'number')
|
||||||
|
member_type = member_type.replace('int64_t', 'number')
|
||||||
|
member_type = member_type.replace('size_t', 'number')
|
||||||
|
member_type = member_type.replace('uintptr_t', 'number')
|
||||||
|
member_type = member_type.replace('...', 'string')
|
||||||
|
member_type = member_type.replace('*', '')
|
||||||
|
member_type = member_type.replace('&', '')
|
||||||
|
member_type = member_type.replace('const', '')
|
||||||
|
member_type = member_type.replace('bool', 'boolean')
|
||||||
|
member_type = member_type.replace('int', 'number')
|
||||||
|
member_type = member_type.replace('float', 'number')
|
||||||
|
member_type = member_type.replace('char', 'string')
|
||||||
|
member_type = member_type.replace('unsigned', 'number')
|
||||||
|
member_type = member_type.replace('u8', 'number')
|
||||||
|
member_type = member_type.replace('u16', 'number')
|
||||||
|
member_type = member_type.replace('u32', 'number')
|
||||||
|
member_type = member_type.replace('u64', 'number')
|
||||||
|
member_type = member_type.replace('s8', 'number')
|
||||||
|
member_type = member_type.replace('s16', 'number')
|
||||||
|
member_type = member_type.replace('s32', 'number')
|
||||||
|
member_type = member_type.replace('s64', 'number')
|
||||||
|
member_type = member_type.replace('void', 'nil')
|
||||||
|
member_type = member_type.replace('f32', 'number')
|
||||||
|
member_type = member_type.replace('f64', 'number')
|
||||||
|
member_type = member_type.replace('double', 'number')
|
||||||
|
member_type = member_type.replace('CONTROLLERBUTTONS_T', 'number')
|
||||||
|
return member_type
|
||||||
|
|
||||||
|
def parse_structs(header):
|
||||||
|
try:
|
||||||
|
with open(header, 'r') as file:
|
||||||
|
lines = file.readlines()
|
||||||
|
except IOError:
|
||||||
|
raise RuntimeError("Failed to open header files for structs node in config")
|
||||||
|
|
||||||
|
struct_regex = re.compile(r"struct\s+(\w+)\s*(?:\s*:\s*(\w+))?[\s\n\r]*\{")
|
||||||
|
|
||||||
|
in_struct = False
|
||||||
|
struct_name = ""
|
||||||
|
found_union = False
|
||||||
|
struct = {}
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
line = line.strip()
|
||||||
|
|
||||||
|
if not in_struct:
|
||||||
|
match = struct_regex.search(line)
|
||||||
|
if match and len(match.groups()) > 1:
|
||||||
|
struct_name = match.group(1)
|
||||||
|
struct[struct_name] = []
|
||||||
|
in_struct = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if 'union' in line:
|
||||||
|
found_union = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if '}' in line and not found_union:
|
||||||
|
in_struct = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
if '}' in line and found_union:
|
||||||
|
found_union = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
line = re.sub(r'(/\*.*?\*/)', '', line)
|
||||||
|
|
||||||
|
if ';' in line and not ':' in line:
|
||||||
|
# if ':' in line:
|
||||||
|
# member_name = line.split(' ')[-3].split(':')[0]
|
||||||
|
# continue
|
||||||
|
if '[' in line:
|
||||||
|
if len(line.split('[')) > 2:
|
||||||
|
continue
|
||||||
|
member_name = line.split('[')[0].split(' ')[-1]
|
||||||
|
member_type = line.split(' ')[-2]
|
||||||
|
else:
|
||||||
|
member_name = line.split(';')[0].split(' ')[-1]
|
||||||
|
member_type = line.split(';')[0].split(' ')[-2]
|
||||||
|
|
||||||
|
|
||||||
|
struct[struct_name].append(member_name + ' ' + sanitize_type(member_type))
|
||||||
|
|
||||||
|
for struct_name, members in struct.items():
|
||||||
|
if len(members) == 0:
|
||||||
|
continue
|
||||||
|
# TODO: Add support for functions
|
||||||
|
print(f'---@class {struct_name}')
|
||||||
|
for i, key in enumerate(members):
|
||||||
|
key = key.replace('*', '')
|
||||||
|
print(f'---@field {key}')
|
||||||
|
print(f'{struct_name} = {{}}')
|
||||||
|
if struct_name == 'Object':
|
||||||
|
print(f'---@return Actor')
|
||||||
|
print(f'function {struct_name}:asActor() end')
|
||||||
|
print(f'---@return Boss')
|
||||||
|
print(f'function {struct_name}:asBoss() end')
|
||||||
|
print(f'---@return Scenery')
|
||||||
|
print(f'function {struct_name}:asScenery() end')
|
||||||
|
print(f'---@return Scenery360')
|
||||||
|
print(f'function {struct_name}:asScenery360() end')
|
||||||
|
print(f'---@return Sprite')
|
||||||
|
print(f'function {struct_name}:asSprite() end')
|
||||||
|
print(f'---@return Item')
|
||||||
|
print(f'function {struct_name}:asItem() end')
|
||||||
|
print(f'---@return Effect')
|
||||||
|
print(f'function {struct_name}:asEffect() end')
|
||||||
|
print(f'---@return {struct_name}')
|
||||||
|
print(f'function {struct_name}:asRef() end')
|
||||||
|
elif struct_name == 'Object' or struct_name == 'ObjectInfo' or struct_name == 'Actor' or struct_name == 'Boss' or struct_name == 'Scenery' or struct_name == 'Scenery360' or struct_name == 'Sprite' or struct_name == 'Item' or struct_name == 'Effect':
|
||||||
|
print(f'---@return {struct_name}')
|
||||||
|
print(f'function {struct_name}:asRef() end')
|
||||||
|
elif struct_name.startswith('Vec') or struct_name.startswith('Plane') or struct_name == 'PosRot' or struct_name == 'CameraPoint' or struct_name == 'Triangle':
|
||||||
|
print(f'---@return {struct_name}')
|
||||||
|
print(f'function {struct_name}:asRef() end')
|
||||||
|
if struct_name.startswith('Vec'):
|
||||||
|
print(f'---@return f32')
|
||||||
|
print(f'function {struct_name}:xRef() end')
|
||||||
|
print(f'---@return f32')
|
||||||
|
print(f'function {struct_name}:yRef() end')
|
||||||
|
print(f'---@return f32')
|
||||||
|
print(f'function {struct_name}:zRef() end')
|
||||||
|
print('')
|
||||||
|
|
||||||
|
def parse_events(header):
|
||||||
|
try:
|
||||||
|
with open(header, 'r') as file:
|
||||||
|
lines = file.readlines()
|
||||||
|
except IOError:
|
||||||
|
raise RuntimeError("Failed to open header files for events node in config")
|
||||||
|
|
||||||
|
global event_list
|
||||||
|
in_event = False
|
||||||
|
event_name = ""
|
||||||
|
event = {}
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
line = line.strip()
|
||||||
|
if not in_event:
|
||||||
|
if 'DEFINE_EVENT' in line:
|
||||||
|
if ');' in line:
|
||||||
|
event_name = line.split('DEFINE_EVENT(')[1].split(')')[0].strip()
|
||||||
|
event[event_name] = ['event IEvent']
|
||||||
|
continue
|
||||||
|
event_name = line.split('DEFINE_EVENT(')[1].split(',')[0].strip()
|
||||||
|
event[event_name] = ['event IEvent']
|
||||||
|
in_event = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ');' in line:
|
||||||
|
in_event = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
if len(line) == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ';' in line:
|
||||||
|
member_name = line.split(';')[0].split(' ')[-1]
|
||||||
|
member_type = line.split(';')[0].split(' ')[-2]
|
||||||
|
event[event_name].append(member_name + ' ' + sanitize_type(member_type))
|
||||||
|
|
||||||
|
for event_name, members in event.items():
|
||||||
|
print(f'---@class {event_name}')
|
||||||
|
event_list.append(event_name)
|
||||||
|
for i, key in enumerate(members):
|
||||||
|
key = key.replace('*', '')
|
||||||
|
print(f'---@field {key}')
|
||||||
|
print('')
|
||||||
|
print('')
|
||||||
|
|
||||||
|
def parse_externs(header, namespace=None):
|
||||||
|
try:
|
||||||
|
with open(header, 'r') as file:
|
||||||
|
lines = file.readlines()
|
||||||
|
except IOError:
|
||||||
|
raise RuntimeError("Failed to open header files for events node in config")
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
line = re.sub(r'\s+', ' ', line.strip())
|
||||||
|
if line.startswith('extern') and not 'void*' in line and not '"C"' in line or ('(' in line and ';' in line):
|
||||||
|
if not '(' in line and not '[' in line:
|
||||||
|
var_type = line.split(' ')[1]
|
||||||
|
var_name = line.split(' ')[2].split(';')[0]
|
||||||
|
print(f'---@return {sanitize_type(var_type)}')
|
||||||
|
print(f'function Game.{var_name}() end')
|
||||||
|
elif '[' in line and not '(' in line:
|
||||||
|
dimension_len = len(line.split('[')) - 1
|
||||||
|
var_name = line.split('[')[0].split(' ')[-1]
|
||||||
|
var_type = line.split(' ')[1]
|
||||||
|
print(f'---@return {sanitize_type(var_type)}[{dimension_len}]')
|
||||||
|
print(f'function Game.{var_name}() end')
|
||||||
|
elif '(' in line:
|
||||||
|
if 'ALIGN_ASSET' in line:
|
||||||
|
var_name = line.split('[')[0].split(' ')[-1]
|
||||||
|
value = line.split('=')[-1].split(';')[0]
|
||||||
|
print('---@type Asset')
|
||||||
|
print(f'Assets.{var_name} = {value.strip()}')
|
||||||
|
continue
|
||||||
|
if 'define' in line or '\\' in line or 'typedef' in line or '[' in line or 'OSMesg' in line or 'Framebuffer' in line or 'TimerAction' in line or 'TimerTask' in line:
|
||||||
|
continue
|
||||||
|
if '_DEG' in line or 'Fault' in line or 'sol:ignore' in line or '<T>' in line or '<' in line:
|
||||||
|
continue
|
||||||
|
func_name = line.split('(')[0].split(' ')[-1]
|
||||||
|
if len(func_name) == 0:
|
||||||
|
continue
|
||||||
|
if 'CVarExists' in func_name or 'ResourceLoad' in func_name or 'void*' in func_name or 'ResourceClearCache' in func_name: # Report this to LUS
|
||||||
|
continue
|
||||||
|
|
||||||
|
return_type = line.split(' ')[0]
|
||||||
|
args = line.split('(')[1].split(')')[0].strip().split(',')
|
||||||
|
for i, arg in enumerate(args):
|
||||||
|
arg = arg.replace('const ', '')
|
||||||
|
arg = arg.replace(' *', '* ')
|
||||||
|
arg = arg.replace('...', 'varargs')
|
||||||
|
if len(arg.split(' ')) > 2:
|
||||||
|
if '=' in arg:
|
||||||
|
arg = arg.split('=')[0]
|
||||||
|
name = arg.split(' ')[2]
|
||||||
|
type = arg.split(' ')[1]
|
||||||
|
else:
|
||||||
|
name = arg.split(' ')[-1]
|
||||||
|
type = arg.split(' ')[-2]
|
||||||
|
else:
|
||||||
|
name = '_'+arg.split(' ')[-1]
|
||||||
|
type = arg.split(' ')[0]
|
||||||
|
|
||||||
|
name = name.replace('*', '')
|
||||||
|
name = name.replace('end', '_end')
|
||||||
|
if(len(name) == 0):
|
||||||
|
name = f'arg{i}'
|
||||||
|
args[i] = { 'name': name, 'type': type }
|
||||||
|
|
||||||
|
for i, arg in enumerate(args):
|
||||||
|
print(f'---@param {arg["name"]} {sanitize_type(arg["type"])}')
|
||||||
|
|
||||||
|
print(f'---@return {sanitize_type(return_type)}')
|
||||||
|
if namespace:
|
||||||
|
print(f'function {namespace}.{func_name}({', '.join([f'{arg["name"]}' for arg in args])}) end')
|
||||||
|
else:
|
||||||
|
print(f'function {func_name}({', '.join([f'{arg["name"]}' for arg in args])}) end')
|
||||||
|
|
||||||
|
def is_blacklisted(file):
|
||||||
|
for item in blacklist:
|
||||||
|
if item in file:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("Game = {}")
|
||||||
|
print("Assets = {}")
|
||||||
|
print("UIWidgets = {}")
|
||||||
|
header = """
|
||||||
|
---@alias ListenerID number
|
||||||
|
---@class Asset
|
||||||
|
local Asset = {}
|
||||||
|
|
||||||
|
--- Registers an asset.
|
||||||
|
function Asset:Register() end
|
||||||
|
|
||||||
|
--- Loads an 8-bit asset.
|
||||||
|
---@return integer
|
||||||
|
function Asset:Load8() end
|
||||||
|
|
||||||
|
--- Loads a 16-bit asset.
|
||||||
|
---@return integer
|
||||||
|
function Asset:Load16() end
|
||||||
|
|
||||||
|
--- Loads a 32-bit asset.
|
||||||
|
---@return integer
|
||||||
|
function Asset:Load32() end
|
||||||
|
|
||||||
|
--- Loads a Vtx asset.
|
||||||
|
---@return Vtx
|
||||||
|
function Asset:LoadVtx() end
|
||||||
|
|
||||||
|
--- Loads a Gfx asset.
|
||||||
|
---@return Gfx
|
||||||
|
function Asset:LoadGfx() end
|
||||||
|
|
||||||
|
--- Converts Asset to string.
|
||||||
|
---@return string
|
||||||
|
function Asset:__tostring() end
|
||||||
|
|
||||||
|
--- Registers an event listener.
|
||||||
|
---@param eventId EventID
|
||||||
|
---@param callback fun(event: EventID)
|
||||||
|
---@param priority EventPriority
|
||||||
|
---@return ListenerID
|
||||||
|
function RegisterListener(eventId, callback, priority) end
|
||||||
|
|
||||||
|
---@class Gfx
|
||||||
|
local Gfx = {}
|
||||||
|
|
||||||
|
--- Returns the next master display list.
|
||||||
|
---@return Gfx
|
||||||
|
function gNextMasterDisp() end
|
||||||
|
|
||||||
|
--- Returns a reference to the master display list.
|
||||||
|
---@return Gfx
|
||||||
|
function gRefMasterDisp() end
|
||||||
|
|
||||||
|
---@class Matrix
|
||||||
|
local Matrix = {}
|
||||||
|
|
||||||
|
--- Returns a reference to the GFX matrix.
|
||||||
|
---@return Matrix
|
||||||
|
function gRefGfxMatrix() end
|
||||||
|
|
||||||
|
--- Sets the primitive color.
|
||||||
|
---@param m number
|
||||||
|
---@param l number
|
||||||
|
---@param r number
|
||||||
|
---@param g number
|
||||||
|
---@param b number
|
||||||
|
---@param a number
|
||||||
|
function gDPSetPrimColor(m, l, r, g, b, a) end
|
||||||
|
"""
|
||||||
|
print(header)
|
||||||
|
for root, dirs, files in os.walk("include"):
|
||||||
|
for file in files:
|
||||||
|
# Join root and file to get full path
|
||||||
|
file_path = os.path.join(root, file)
|
||||||
|
# Check if the file is blacklisted
|
||||||
|
if(is_blacklisted(file_path)):
|
||||||
|
continue
|
||||||
|
|
||||||
|
parse_enums(file_path, True if 'scripting.h' in file_path else False)
|
||||||
|
parse_structs(file_path)
|
||||||
|
parse_externs(file_path)
|
||||||
|
|
||||||
|
parse_enums("src/port/hooks/impl/EventSystem.h")
|
||||||
|
parse_structs("src/port/hooks/impl/EventSystem.h")
|
||||||
|
parse_externs("libultraship/src/public/bridge/consolevariablebridge.h")
|
||||||
|
|
||||||
|
parse_enums("src/port/Engine.h")
|
||||||
|
parse_externs("src/port/Engine.h")
|
||||||
|
parse_externs("src/port/ui/UIWidgets.h", 'UIWidgets')
|
||||||
|
parse_externs("libultraship/src/public/bridge/resourcebridge.h")
|
||||||
|
|
||||||
|
for root, dirs, files in os.walk("src/port/hooks/list"):
|
||||||
|
for file in files:
|
||||||
|
parse_events(os.path.join(root, file))
|
||||||
|
|
||||||
|
print('---@enum EventID')
|
||||||
|
print('EventID = {')
|
||||||
|
for event_name in event_list:
|
||||||
|
print(f' {event_name} = -1' + (',' if event_name != event_list[-1] else ''))
|
||||||
|
print('}')
|
Loading…
Add table
Add a link
Reference in a new issue