sm64coopdx/autogen/convert_structs.py
Cooliokid956 3bfa75e32b
Some checks are pending
Build coop / build-ubuntu (push) Waiting to run
Build coop / build-windows (push) Waiting to run
Build coop / build-macos-arm (push) Waiting to run
Build coop / build-macos-intel (push) Waiting to run
Miscellaneous Additions: Addendum (#723)
* More autogen work

- made the `Pointer_` classes into aliases instead so that they're actually associated with their true type
- "Total constants" metric is now accurate

* High Quality Master Volume

* Audio work

it's 12:55am and there are some bright flashes outside (lightning)

- cracked the code (interpreted the "Acc" in `tempoAcc`)
- added several functions that will help greatly in the Streamed Music department (you can now match sequenced music fading (transitions, eepy, etc.))
- introducing `gMasterVolume`! a variable that is only updated when it needs to be, theoretically improving performance (by some amount). this variable is used in many places in place of recalculations of the same number
- made it so that muting the game skips some audio processing (not the main process since that would linger after unmuting (not good))
- fixed an oversight where lua volumes were not taken into account when `audio_stream_set_volume`
- it's its 😁
- removed additional `#include "audio/external.h"`

it is 1:06am
gn

* Add mouse status functions

you can now check if mouse buttons were held, clicked, or released

* Sorting was a bad idea

disabled sorting for constants so that they are represented more closely to their original defines

* Expose playerlist page index

also noticed that sorting still sucks

* Minor (very important) detail

lalette

* Addressing the PeachyPeachSM64 reviews

* Return of the Forced 4:3 Mode

shoutouts to DISPLAY.FORCE_4BY3 for sticking through the toughest of times, waiting for this day to come

* Added scroll support

- Scrolling added to chat box (hold ctrl to scroll fewer lines, shift to scroll faster)
- Scrolling functions added to smlua

* Addressing the Isaac0-dev review + fixes

- mouse scroll is now accumulated
- djui_gfx_get_dimensions
- forced 4:3 won't kick in if the window isn't wide enough
- game now recognizes horizontal resizing when in 4:3 mode

* Run autogen

* gfx_get_dimensions

works just as well
2025-04-05 13:52:14 -04:00

821 lines
25 KiB
Python

import os
import re
import sys
from extract_structs import *
from extract_object_fields import *
from common import *
from vec_types import *
in_files = [
"include/types.h",
"src/game/area.h",
"src/game/camera.h",
"src/game/characters.h",
"src/engine/surface_collision.h",
"src/pc/network/network_player.h",
"src/pc/djui/djui_hud_utils.h",
"src/pc/djui/djui_theme.h",
"src/game/object_helpers.h",
"src/game/mario_step.h",
"src/pc/lua/utils/smlua_anim_utils.h",
"src/pc/lua/utils/smlua_misc_utils.h",
"src/pc/lua/utils/smlua_camera_utils.h",
"src/pc/lua/utils/smlua_collision_utils.h",
"src/pc/lua/utils/smlua_level_utils.h",
"src/game/spawn_sound.h",
"src/pc/network/network.h",
"src/game/hardcoded.h",
"src/pc/mods/mod.h",
"src/pc/lua/utils/smlua_audio_utils.h",
"src/game/paintings.h",
"src/pc/djui/djui_types.h",
"src/game/first_person_cam.h",
"src/game/player_palette.h",
"src/engine/graph_node.h",
"include/PR/gbi.h"
]
out_filename_c = 'src/pc/lua/smlua_cobject_autogen.c'
out_filename_h = 'src/pc/lua/smlua_cobject_autogen.h'
out_filename_docs = 'docs/lua/structs.md'
out_filename_defs = 'autogen/lua_definitions/structs.lua'
c_template = """/* THIS FILE IS AUTOGENERATED */
/* SHOULD NOT BE MANUALLY CHANGED */
$[INCLUDES]
#include "include/object_fields.h"
$[BODY]
const char *smlua_get_lot_name(u16 lot) {
assert(smlua_valid_lot(lot)); // if this is false, it means there's an invalid lot somewhere
return sLuaLotNames[lot];
}
struct LuaObjectField* smlua_get_object_field_autogen(u16 lot, const char* key) {
struct LuaObjectTable* ot = &sLuaObjectAutogenTable[lot - LOT_AUTOGEN_MIN - 1];
return smlua_get_object_field_from_ot(ot, key);
}
"""
h_template = """/* THIS FILE IS AUTOGENERATED */
/* SHOULD NOT BE MANUALLY CHANGED */
#ifndef SMLUA_COBJECT_AUTOGEN_H
#define SMLUA_COBJECT_AUTOGEN_H
$[BODY]
const char *smlua_get_lot_name(u16 lot);
struct LuaObjectField* smlua_get_object_field_autogen(u16 lot, const char* key);
#endif
"""
override_field_names = {
}
override_field_types = {
"Surface": { "normal": "Vec3f" },
"Object": { "oAnimations": "ObjectAnimPointer*" },
}
override_field_mutable = {
"NetworkPlayer": [
"overrideModelIndex",
"overridePalette",
"overridePaletteIndex"
],
"Animation": [
"values",
"index",
],
}
override_field_invisible = {
"Mod": [ "files", "showedScriptWarning" ],
"MarioState": [ "visibleToEnemies" ],
"NetworkPlayer": [ "gag", "moderator", "discordId" ],
"GraphNode": [ "_guard1", "_guard2" ],
"FnGraphNode": [ "luaTokenIndex" ],
"Object": [ "firstSurface" ],
"ModAudio": [ "sound", "decoder", "buffer", "bufferSize", "sampleCopiesTail" ],
}
override_field_deprecated = {
"NetworkPlayer": [ "paletteIndex", "overridePaletteIndex", "overridePaletteIndexLp" ]
}
override_field_immutable = {
"MarioState": [ "playerIndex", "controller", "marioObj", "marioBodyState", "statusForCamera", "area", "dialogId" ],
"MarioAnimation": [ "animDmaTable" ],
"ObjectNode": [ "next", "prev" ],
"Character": [ "*" ],
"NetworkPlayer": [ "*" ],
"TextureInfo": [ "*" ],
"Object": ["oSyncID", "coopFlags", "oChainChompSegments", "oWigglerSegments", "oHauntedChairUnk100", "oTTCTreadmillBigSurface", "oTTCTreadmillSmallSurface", "bhvStackIndex", "respawnInfoType", "numSurfaces" ],
"GlobalObjectAnimations": [ "*"],
"SpawnParticlesInfo": [ "model" ],
"MarioBodyState": [ "updateTorsoTime" ],
"Area": [ "localAreaTimer", "nextSyncID", "unk04", "objectSpawnInfos", "paintingWarpNodes", "warpNodes" ],
"Mod": [ "*" ],
"ModFile": [ "*" ],
"Painting": [ "id", "imageCount", "textureType", "textureWidth", "textureHeight" ],
"SpawnInfo": [ "syncID", "next", "unk18" ],
"CustomLevelInfo": [ "next" ],
"GraphNode": [ "children", "next", "parent", "prev", "type" ],
"GraphNodeBackground": [ "prevCameraTimestamp", "unused" ],
"GraphNodeCamera": [ "matrixPtrPrev", "prevTimestamp" ],
"GraphNodeHeldObject": [ "prevShadowPosTimestamp" ],
"GraphNodeObject": [ "angle", "animInfo", "cameraToObject", "node", "pos", "prevAngle", "prevPos", "prevScale", "prevScaleTimestamp", "prevShadowPos", "prevShadowPosTimestamp", "prevThrowMatrix", "prevThrowMatrixTimestamp", "prevTimestamp", "scale", "shadowPos", "sharedChild", "skipInterpolationTimestamp", "throwMatrixPrev", "unk4C", ],
"GraphNodeObjectParent": [ "sharedChild" ],
"GraphNodePerspective": [ "unused" ],
"GraphNodeSwitchCase": [ "fnNode", "numCases", "unused" ],
"ObjectWarpNode": [ "next "],
"Animation": [ "length" ],
"AnimationTable": [ "count" ],
"Controller": [ "controllerData", "statusData" ],
"FirstPersonCamera": [ "enabled" ],
"ModAudio": [ "isStream", "loaded" ],
"Gfx": [ "w0", "w1" ], # to protect from invalid type conversions
}
override_field_version_excludes = {
"oCameraLakituUnk104": "VERSION_JP",
"oCoinUnk1B0": "VERSION_JP"
}
override_allowed_structs = {
"src/pc/network/network.h": [ "ServerSettings", "NametagsSettings" ],
"src/pc/djui/djui_types.h": [ "DjuiColor" ],
"src/game/player_palette.h": [ "PlayerPalette" ],
"include/PR/gbi.h": [ "Gfx", "Vtx" ]
}
sLuaManuallyDefinedStructs = [{
'path': 'n/a',
'structs': [
*['struct %s { %s }' % (
type_name,
' '.join([
'%s %s;' % (vec_type['field_c_type'], lua_field)
for lua_field in vec_type['fields_mapping'].keys()
])
) for type_name, vec_type in VEC_TYPES.items()]
]
}]
override_types = {
"Gwords": "Gfx",
"Vtx_t": "Vtx"
}
reversed_override_types = {v: k for k, v in override_types.items()}
total_structs = 0
total_fields = 0
############################################################################
def promote_block(before_block, after_block):
inside = 1
idx = -1
for character in after_block:
idx += 1
if character == '{':
inside += 1
elif character == '}':
inside -= 1
if inside <= 0:
break
if inside == 0 and idx > -1 and after_block[idx+1] == ';':
return before_block + after_block[:idx] + after_block[idx+2:]
return None
def strip_anonymous_blocks(body):
while 'union {' in body:
before_union = body.split('union {', 1)[0]
after_union = body.split('union {', 1)[-1]
promoted = promote_block(before_union, after_union)
if promoted == None:
break
body = promoted
while 'struct {' in body:
before_union = body.split('struct {', 1)[0]
after_union = body.split('struct {', 1)[-1]
promoted = promote_block(before_union, after_union)
if promoted == None:
break
body = promoted
return body
def strip_internal_blocks(body):
# strip internal structs/enums/etc
tmp = body
body = ''
inside = 0
stripped = ''
for character in tmp:
if character == '{':
body += '{ ... }'
inside += 1
if inside == 0:
body += character
else:
stripped += character
if character == '}':
inside -= 1
return body
def identifier_to_caps(identifier):
caps = ''
was_cap = True
for c in identifier:
if c >= 'A' and c <= 'Z':
if not was_cap:
caps += '_'
was_cap = True
else:
was_cap = False
caps += c.upper()
return caps
def table_to_string(table):
count = 0
columns = 0
column_width = []
for c in table[0]:
column_width.append(0)
columns += 1
for row in table:
for i in range(columns):
if '#' in row[i]:
continue
if len(row[i]) > column_width[i]:
column_width[i] = len(row[i])
s = ''
for row in table:
line = ''
for i in range(columns):
line += row[i].ljust(column_width[i])
if '???' in line:
line = '//' + line[2:] + ' <--- UNIMPLEMENTED'
else:
count += 1
s += line + '\n'
return s, count
############################################################################
def parse_struct(struct_str, sortFields = True):
struct = {}
match = re.match(r"struct\s*(\w+)?\s*{(.*?)}\s*(\w+)?\s*", struct_str.replace("typedef ", ""), re.DOTALL)
struct_name, body, trailing_name = match.groups()
identifier = struct_name if struct_name else trailing_name
if identifier in override_types:
identifier = override_types[identifier]
struct['identifier'] = identifier
struct['typedef'] = 'typedef ' in struct_str
body = struct_str.split('{', 1)[1].rsplit('}', 1)[0]
body = strip_anonymous_blocks(body)
body = strip_internal_blocks(body)
struct['fields'] = []
field_strs = body.split(';')
for field_str in field_strs:
if len(field_str.strip()) == 0:
continue
if '*' in field_str:
field_type, field_id = field_str.strip().rsplit('*', 1)
field_type = field_type.strip() + '*'
else:
split_parts = re.split(r'\s+', field_str.strip())
field_type = ' '.join(split_parts[:-1])
field_id = split_parts[-1]
if '[' in field_id:
array_str = '[' + field_id.split('[', 1)[1]
field_id = field_id.split('[', 1)[0]
if array_str != '[1]':
field_type += ' ' + array_str
field = {}
field['type'] = field_type.strip()
field['identifier'] = field_id.strip()
field['field_str'] = field_str
struct['fields'].append(field)
if identifier == 'Object':
struct['fields'] += extract_object_fields()
if sortFields:
struct['fields'] = sorted(struct['fields'], key=lambda d: d['identifier'])
return struct
def parse_structs(extracted, sortFields = True):
structs = []
for e in extracted:
for struct in e['structs']:
parsed = parse_struct(struct, sortFields)
if e['path'] in override_allowed_structs:
if parsed['identifier'] not in override_allowed_structs[e['path']]:
continue
structs.append(parsed)
return structs
############################################################################
fuzz_from = ""
fuzz_to = ""
fuzz_structs = ""
fuzz_structs_calls = ""
fuzz_template_str = None
def output_fuzz_struct_calls(struct):
sid = struct['identifier']
global fuzz_template_str
if fuzz_template_str == None:
with open(fuzz_from) as f:
fuzz_template_str = f.read()
global fuzz_structs_calls
rnd_call = 'rnd_' + sid + '()'
if rnd_call in fuzz_template_str:
fuzz_structs_calls += ' function() Fuzz' + sid + '(rnd_' + sid + '()) end,\n'
else:
fuzz_structs_calls += ' -- function() Fuzz' + sid + '(rnd_' + sid + '()) end,\n'
def output_fuzz_struct(struct):
output_fuzz_struct_calls(struct)
sid = struct['identifier']
s_out = 'function Fuzz' + sid + "(struct)\n"
s_out += ' local funcs = {\n'
for field in struct['fields']:
fid, ftype, fimmutable, lvt, lot, size = get_struct_field_info(struct, field)
if fimmutable == 'true':
continue
if sid in override_field_invisible:
if fid in override_field_invisible[sid]:
continue
if '(' in fid or '[' in fid or ']' in fid:
continue
ptype, plink = translate_type_to_lua(ftype)
rnd_line = translate_type_to_rnd(ptype)
s_out += ' function() '
if lvt == 'LVT_COBJECT':
s_out += 'Fuzz' + ftype.replace('struct ', '') + '(struct.' + fid + ')'
elif lvt == 'LVT_COBJECT_P':
s_out += 'struct.' + fid + ' = ' + rnd_line + ''
else:
s_out += 'struct.' + fid + ' = ' + rnd_line + ''
s_out += ' end,\n'
s_out += ' }\n'
s_out += """
for i = #funcs, 2, -1 do
local j = math.random(i)
funcs[i], funcs[j] = funcs[j], funcs[i]
end
for k,v in pairs(funcs) do
v()
end
"""
s_out += 'end\n\n'
global fuzz_structs
fuzz_structs += s_out
def output_fuzz_file():
global fuzz_structs
global fuzz_structs_calls
with open(fuzz_from) as f:
file_str = f.read()
with open(fuzz_to, 'w') as f:
f.write(file_str.replace('-- $[STRUCTS]', fuzz_structs).replace('-- $[FUZZ-STRUCTS]', fuzz_structs_calls))
############################################################################
def build_vec_types():
s = gen_comment_header("vec types")
for type_name, vec_type in VEC_TYPES.items():
optional_fields = vec_type.get('optional_fields_mapping', {})
s += '#define LUA_%s_FIELD_COUNT %d\n' % (type_name.upper(), len(vec_type['fields_mapping']) + len(optional_fields))
s += 'static struct LuaObjectField s%sFields[LUA_%s_FIELD_COUNT] = {\n' % (type_name, type_name.upper())
field_c_type = vec_type['field_c_type']
combined_fields = [
(index, field_name)
for mapping in [vec_type['fields_mapping'], optional_fields]
for index, field_name in enumerate(mapping.keys())
]
sorted_fields_with_order = sorted(combined_fields, key=lambda x: x[1]) # sort alphabetically
for original_index, lua_field in sorted_fields_with_order:
s += ' { "%s", LVT_%s, sizeof(%s) * %d, false, LOT_NONE, 1, sizeof(%s) },\n' % (lua_field, field_c_type.upper(), field_c_type, original_index, field_c_type)
s += '};\n\n'
s += 'struct LuaObjectTable sLuaObjectTable[LOT_MAX] = {\n'
s += ' [LOT_NONE] = { LOT_NONE, NULL, 0 },\n'
for type_name in VEC_TYPES.keys():
s += ' [LOT_%s] = { LOT_%s, s%sFields, LUA_%s_FIELD_COUNT },\n' % (type_name.upper(), type_name.upper(), type_name, type_name.upper())
s += ' [LOT_ARRAY] = { LOT_ARRAY, NULL, 0 },\n'
s += ' [LOT_POINTER] = { LOT_POINTER, NULL, 0 },\n'
s += '};\n\n'
return s
############################################################################
sLuaObjectTable = []
sLotAutoGenList = []
def get_struct_field_info(struct, field):
sid = struct['identifier']
fid = field['identifier']
ftype = field['type']
size = 1
if sid in override_field_names and fid in override_field_names[sid]:
fid = override_field_names[sid][fid]
if sid in override_field_types and fid in override_field_types[sid]:
ftype = override_field_types[sid][fid]
lvt = translate_type_to_lvt(ftype, allowArrays=True)
lot = translate_type_to_lot(ftype, allowArrays=True)
fimmutable = str(lvt == 'LVT_COBJECT' or 'const ' in ftype).lower()
if lvt.startswith('LVT_') and lvt.endswith('_P') and 'OBJECT' not in lvt and 'COLLISION' not in lvt and 'TRAJECTORY' not in lvt:
fimmutable = 'true'
if sid in override_field_immutable:
if fid in override_field_immutable[sid] or '*' in override_field_immutable[sid]:
fimmutable = 'true'
if sid in override_field_mutable:
if fid in override_field_mutable[sid] or '*' in override_field_mutable[sid]:
fimmutable = 'false'
if not ('char' in ftype and '[' in ftype and 'unsigned' not in ftype):
array_match = re.search(r'\[([^\]]+)\]', ftype)
if array_match:
array_size = array_match.group(1).strip()
if array_size.isdigit():
size = int(array_size)
elif array_size.startswith("0x") and all(c in "0123456789abcdef" for c in array_size[2:]):
size = int(array_size, 16)
else:
lvt, lot = 'LVT_???', "LOT_???" # array size not provided, so not supported
return fid, ftype, fimmutable, lvt, lot, size
def build_struct(struct):
# debug print out lua fuzz functions
if len(sys.argv) >= 2 and sys.argv[1] == 'fuzz':
output_fuzz_struct(struct)
sid = struct['identifier']
# build up table and track column width
field_table = []
for field in struct['fields']:
fid, ftype, fimmutable, lvt, lot, size = get_struct_field_info(struct, field)
if re.search(r'\[([^\]]+)\]', ftype):
ftype = re.sub(r'\[[^\]]*\]', '', ftype).strip()
if sid in override_field_invisible:
if fid in override_field_invisible[sid]:
continue
name = sid
if sid in reversed_override_types:
name = reversed_override_types[sid]
version = None
row = []
struct_str = "struct " if not struct['typedef'] else ""
startStr = ''
endStr = ' },'
if fid in override_field_version_excludes:
startStr += '#ifndef ' + override_field_version_excludes[fid] + '\n'
endStr += '\n#endif'
startStr += ' { '
row.append(startStr )
row.append('"%s", ' % fid )
row.append('%s, ' % lvt )
row.append('offsetof(%s%s, %s), ' % (struct_str, name, field['identifier']))
row.append('%s, ' % fimmutable )
row.append('%s, ' % lot )
row.append('%s, ' % size )
row.append('sizeof(%s)' % ftype )
row.append(endStr )
field_table.append(row)
field_table_str, field_count = table_to_string(field_table)
field_count_define = 'LUA_%s_FIELD_COUNT' % identifier_to_caps(sid)
struct_lot = 'LOT_%s' % sid.upper()
s = "#define %s $[STRUCTFIELDCOUNT]\n" % field_count_define
s += "static struct LuaObjectField s%sFields[%s] = {\n" % (sid, field_count_define)
s += field_table_str
s += '};\n'
s = s.replace('$[STRUCTFIELDCOUNT]', str(field_count))
global sLuaObjectTable
struct_row = []
struct_row.append(' { ' )
struct_row.append('%s, ' % struct_lot )
struct_row.append('s%sFields, ' % sid )
struct_row.append('%s ' % field_count_define )
struct_row.append('},' )
sLuaObjectTable.append(struct_row)
global sLotAutoGenList
sLotAutoGenList.append(struct_lot)
return s
def build_structs(structs):
global sLuaObjectTable
sLuaObjectTable = []
global sLotAutoGenList
sLotAutoGenList = []
s = ''
for struct in structs:
if struct['identifier'] in exclude_structs:
continue
s += build_struct(struct) + '\n'
return s
def build_body(parsed):
built = build_vec_types()
built += gen_comment_header("autogen types")
built += build_structs(parsed)
obj_table_row_built, obj_table_count = table_to_string(sLuaObjectTable)
obj_table_built = 'struct LuaObjectTable sLuaObjectAutogenTable[LOT_AUTOGEN_MAX - LOT_AUTOGEN_MIN] = {\n'
obj_table_built += obj_table_row_built
obj_table_built += '};\n'
lot_names = '\nconst char *sLuaLotNames[] = {\n'
for type_name in VEC_TYPES.keys():
lot_names += f'\t[LOT_{type_name.upper()}] = "{type_name}",\n'
lot_names += f'\t[LOT_ARRAY] = "Array",\n'
lot_names += f'\t[LOT_POINTER] = "Pointer",\n'
lot_names += f'\t[LOT_MAX] = "Max",\n'
lot_names += '\n'
for struct in parsed:
sid = struct['identifier']
if sid in exclude_structs:
continue
lot_names += f'\t[LOT_{sid.upper()}] = "{sid}",\n'
lot_names += '};\n'
return built + obj_table_built + lot_names
def build_lot_enum():
s = ''
s += 'enum LuaObjectType {\n'
s += ' LOT_NONE = 0,\n'
for type_name in VEC_TYPES.keys():
s += ' LOT_%s,\n' % (type_name.upper())
s += ' LOT_ARRAY,\n'
s += ' LOT_POINTER,\n'
s += ' LOT_MAX,\n'
s += '};\n\n'
s += 'enum LuaObjectAutogenType {\n'
s += ' LOT_AUTOGEN_MIN = 1000,\n'
global sLotAutoGenList
for lot in sLotAutoGenList:
s += ' ' + lot + ',\n'
s += ' LOT_AUTOGEN_MAX,\n'
s += '};\n'
return s
def build_includes():
s = '#include "smlua.h"\n'
for in_file in in_files:
s += '#include "%s"\n' % in_file
return s
############################################################################
def doc_struct_index(structs):
s = '# Supported Structs\n'
for struct in structs:
sid = struct['identifier']
s += '- [%s](#%s)\n' % (sid, sid)
global total_structs
total_structs += 1
s += '\n<br />\n\n'
return s
def doc_struct_field(struct, field):
fid, ftype, fimmutable, lvt, lot, size = get_struct_field_info(struct, field)
sid = struct['identifier']
if sid in override_field_invisible:
if fid in override_field_invisible[sid]:
return ''
if sid in override_field_deprecated:
if fid in override_field_deprecated[sid]:
return ''
if '???' in lvt or '???' in lot:
return ''
ftype, flink = translate_type_to_lua(ftype)
restrictions = ('', 'read-only')[fimmutable == 'true']
global total_fields
total_fields += 1
if flink:
return '| %s | [%s](%s) | %s |\n' % (fid, ftype, flink, restrictions)
return '| %s | %s | %s |\n' % (fid, ftype, restrictions)
def doc_struct_object_fields(struct):
fields = extract_object_fields()
s = '\n### Object-Independent Data Fields\n'
s += "| Field | Type | Access |\n"
s += "| ----- | ---- | ------ |\n"
for field in fields:
if field['identifier'] == 'oPathedStartWaypoint':
s += '\n### Object-Dependent Data Fields\n'
s += "| Field | Type | Access |\n"
s += "| ----- | ---- | ------ |\n"
s += doc_struct_field(struct, field)
return s
def doc_struct(struct):
sid = struct['identifier']
s = '## [%s](#%s)\n\n' % (sid, sid)
s += "| Field | Type | Access |\n"
s += "| ----- | ---- | ------ |\n"
# build doc table
field_table = []
for field in struct['fields']:
if 'object_field' in field and field['object_field'] == True:
continue
s += doc_struct_field(struct, field)
if sid == 'Object':
s += doc_struct_object_fields(struct)
s += '\n[:arrow_up_small:](#)\n\n<br />\n'
return s
def doc_structs(structs):
structs.extend(parse_structs(sLuaManuallyDefinedStructs, False)) # Don't sort fields for vec types in the documentation
structs = sorted(structs, key=lambda d: d['identifier'])
s = '## [:rewind: Lua Reference](lua.md)\n\n'
s += doc_struct_index(structs)
for struct in structs:
if struct['identifier'] in exclude_structs:
continue
s += doc_struct(struct) + '\n'
with open(get_path(out_filename_docs), 'w', newline='\n') as out:
out.write(s)
############################################################################
def_pointers = []
def def_struct(struct):
sid = struct['identifier']
stype = translate_to_def(sid)
if stype.startswith('Pointer_') and stype not in def_pointers:
def_pointers.append(stype)
s = '\n--- @class %s\n' % stype
for field in struct['fields']:
fid, ftype, fimmutable, lvt, lot, size = get_struct_field_info(struct, field)
if sid in override_field_invisible:
if fid in override_field_invisible[sid]:
continue
if '???' in lvt or '???' in lot:
continue
ftype, flink = translate_type_to_lua(ftype)
ftype = translate_to_def(ftype)
if ftype.startswith('Pointer_') and ftype not in def_pointers:
def_pointers.append(ftype)
s += '--- @field public %s %s\n' % (fid, ftype)
return s
def def_structs(structs):
s = '-- AUTOGENERATED FOR CODE EDITORS --\n'
for struct in structs:
if struct['identifier'] in exclude_structs:
continue
s += def_struct(struct)
s += '\n'
for def_pointer in def_pointers:
s += '--- @alias %s %s\n' % (def_pointer, def_pointer[8:])
with open(get_path(out_filename_defs), 'w', newline='\n') as out:
out.write(s)
############################################################################
def build_files():
extracted = []
for in_file in in_files:
path = get_path(in_file)
extracted.append({
'path': in_file,
'structs': extract_structs(path)
})
parsed = parse_structs(extracted)
parsed = sorted(parsed, key=lambda d: d['identifier'])
built_body = build_body(parsed)
built_enum = build_lot_enum()
built_include = build_includes()
out_c_filename = get_path(out_filename_c)
with open(out_c_filename, 'w', newline='\n') as out:
out.write(c_template.replace("$[BODY]", built_body).replace('$[INCLUDES]', built_include))
out_h_filename = get_path(out_filename_h)
with open(out_h_filename, 'w', newline='\n') as out:
out.write(h_template.replace("$[BODY]", built_enum))
doc_structs(parsed)
def_structs(parsed)
if len(sys.argv) >= 2 and sys.argv[1] == 'fuzz':
output_fuzz_file()
global total_structs
global total_fields
print("Total structs: " + str(total_structs))
print("Total fields: " + str(total_fields))
############################################################################
if __name__ == '__main__':
build_files()