mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-28 23:13:02 +00:00
c428612a9e
* Properly set Mario's y vel to 0 on popping * Change 0 to 0.0f, just in case * Re-introduce a few vanilla bugs under gBehaviorValues The Shell Mario glitch was patched as a side effect to patching a different bug, but several romhacks use it so I need it back. The ability to collect multiple normal caps at once is needed for hat-in-hand using the hat factory glitch. * Fix Shell Mario fix Found the actual reason why the glitch doesn't work and figured that this change shouldn't affect anything else, so I removed its entry from gBehaviorValues. * Add InfiniteRenderDistance to gBehaviorValues I'm well aware that disabling the infinite render distance will be very desync prone, however a few glitches, most notably cloning and chuckya double jump, need objects load and unload from render distance. * Allow mods to disable the camera centering from romhack camera * Allow mods to disable romhack camera centering Done again * Update on network shutdown * Remove a line which I have no idea why it returned * Add set_exclamation_box_contents() No way this is memory safe or even well made but I did what I could * Added (most of) peachy's suggestions Still need to figure out how to stop the game from reading further than the size of the array without using a hardcoded number * Added more of peachy's suggestions I figured a good way to cap how far the exclamation box reads is to pass in the length of the array as well
377 lines
10 KiB
Python
377 lines
10 KiB
Python
import os
|
|
from xml.etree.ElementInclude import include
|
|
from common import *
|
|
from extract_constants import *
|
|
|
|
in_filename = 'autogen/lua_constants/built-in.lua'
|
|
out_filename = 'src/pc/lua/smlua_constants_autogen.c'
|
|
out_filename_docs = 'docs/lua/constants.md'
|
|
out_filename_defs = 'autogen/lua_definitions/constants.lua'
|
|
|
|
in_files = [
|
|
"include/types.h",
|
|
"include/sm64.h",
|
|
"src/pc/lua/smlua_hooks.h",
|
|
"src/game/area.h",
|
|
"src/game/camera.h",
|
|
"include/mario_animation_ids.h",
|
|
"include/sounds.h",
|
|
"src/game/characters.h",
|
|
"src/pc/network/network.h",
|
|
"src/pc/network/network_player.h",
|
|
"include/PR/os_cont.h",
|
|
"src/game/interaction.c",
|
|
"src/game/interaction.h",
|
|
"src/pc/djui/djui_hud_utils.h",
|
|
"include/behavior_table.h",
|
|
"src/pc/lua/utils/smlua_model_utils.h",
|
|
"src/pc/lua/utils/smlua_misc_utils.h",
|
|
"include/object_constants.h",
|
|
"include/mario_geo_switch_case_ids.h",
|
|
"src/game/object_list_processor.h",
|
|
"src/engine/graph_node.h",
|
|
"levels/level_defines.h",
|
|
"src/game/obj_behaviors.c",
|
|
"src/game/save_file.h",
|
|
"src/game/obj_behaviors_2.h",
|
|
"include/dialog_ids.h",
|
|
"include/seq_ids.h",
|
|
"include/surface_terrains.h",
|
|
"src/game/level_update.h",
|
|
"src/pc/network/version.h",
|
|
"include/geo_commands.h",
|
|
"include/level_commands.h",
|
|
"src/audio/external.h",
|
|
"src/game/envfx_snow.h",
|
|
"src/pc/mods/mod_storage.cpp.h"
|
|
]
|
|
|
|
exclude_constants = {
|
|
'*': [ '^MAXCONTROLLERS$', '^AREA_[^T].*', '^AREA_T[HTO]', '^CONT_ERR.*', '^READ_MASK$', '^SIGN_RANGE$', ],
|
|
'src/game/obj_behaviors.c': ['^o$'],
|
|
}
|
|
|
|
include_constants = {
|
|
'include/geo_commands.h': ['BACKGROUND'],
|
|
'include/level_commands.h': [ "WARP_CHECKPOINT", "WARP_NO_CHECKPOINT" ],
|
|
'src/audio/external.h': [ "SEQ_PLAYER" ],
|
|
'src/pc/mods/mod_storage.cpp.h': [ "MAX_KEYS", "MAX_KEY_VALUE_LENGTH" ]
|
|
}
|
|
|
|
pretend_find = [
|
|
'SOUND_ARG_LOAD'
|
|
]
|
|
############################################################################
|
|
|
|
seen_constants = []
|
|
totalConstants = 0
|
|
|
|
############################################################################
|
|
|
|
def validate_identifiers(built_files):
|
|
all_identifiers = [x.group()[1:] for x in re.finditer(r'[(, ][A-Z_][A-Z0-9_]*', built_files)]
|
|
all_identifiers = set(all_identifiers)
|
|
for ident in all_identifiers:
|
|
if ident in pretend_find:
|
|
continue
|
|
if ident + ' = ' not in built_files:
|
|
print('COULD NOT FIND ' + ident)
|
|
|
|
|
|
############################################################################
|
|
|
|
def saw_constant(identifier):
|
|
if identifier in seen_constants:
|
|
print("SAW DUPLICATE CONSTANT: " + identifier)
|
|
return True
|
|
else:
|
|
global totalConstants
|
|
totalConstants += 1
|
|
seen_constants.append(identifier)
|
|
return False
|
|
|
|
def allowed_identifier(filename, ident):
|
|
exclude_list = exclude_constants['*']
|
|
|
|
if filename in exclude_constants:
|
|
exclude_list.extend(exclude_constants[filename])
|
|
|
|
for exclude in exclude_list:
|
|
if re.search(exclude, ident) != None:
|
|
return False
|
|
|
|
if filename in include_constants:
|
|
for include in include_constants[filename]:
|
|
if re.search(include, ident) != None:
|
|
return True
|
|
return False
|
|
|
|
return True
|
|
|
|
def process_enum(filename, line):
|
|
_, ident, val = line.split(' ', 2)
|
|
|
|
if '{' not in val or '}' not in val:
|
|
#print('UNRECOGNIZED ENUM: ' + line)
|
|
return None
|
|
|
|
# grab inside body
|
|
val = val.split('{', 1)[-1].rsplit('}', 1)[0]
|
|
|
|
ret = {}
|
|
ret['identifier'] = ident
|
|
|
|
constants = []
|
|
set_to = None
|
|
index = 0
|
|
fields = val.split(',')
|
|
for field in fields:
|
|
field = field.strip()
|
|
if len(field) == 0:
|
|
continue
|
|
|
|
if '=' in field:
|
|
ident, val = field.split('=', 2)
|
|
constants.append([ident.strip(), val.strip()])
|
|
set_to = ident
|
|
index = 1
|
|
continue
|
|
|
|
if set_to is not None:
|
|
constants.append([field, '((%s) + %d)' % (set_to, index)])
|
|
index += 1
|
|
continue
|
|
|
|
if allowed_identifier(filename, field):
|
|
constants.append([field, str(index)])
|
|
|
|
if saw_constant(field):
|
|
print('>>> ' + line)
|
|
|
|
index += 1
|
|
|
|
ret['constants'] = constants
|
|
|
|
return ret
|
|
|
|
|
|
def process_define(filename, line):
|
|
_, ident, val = line.split(' ', 2)
|
|
|
|
val = val.replace('(u8)', '')
|
|
val = val.replace('(u64)', '')
|
|
|
|
for p in val.split(' '):
|
|
if p.startswith('0x'):
|
|
continue
|
|
p = re.sub(r'0x[a-fA-F0-9]+', '', p)
|
|
if re.search('[a-z]', p) != None and 'VERSION_TEXT' not in line:
|
|
if 'gCurrentObject' not in line:
|
|
print('UNRECOGNIZED DEFINE: ' + line)
|
|
return None
|
|
|
|
if not allowed_identifier(filename, ident):
|
|
return None
|
|
|
|
if saw_constant(ident):
|
|
print('>>> ' + line)
|
|
|
|
return [ident, val]
|
|
|
|
|
|
def process_line(filename, line):
|
|
if line.startswith('enum '):
|
|
return process_enum(filename, line)
|
|
elif line.startswith('#define '):
|
|
return process_define(filename, line)
|
|
else:
|
|
print("UNRECOGNIZED LINE: " + line)
|
|
return None
|
|
|
|
def process_file(filename):
|
|
processed_file = {}
|
|
processed_file['filename'] = filename.replace('\\', '/').split('/')[-1]
|
|
|
|
constants = []
|
|
lines = extract_constants(get_path(filename)).splitlines()
|
|
for line in lines:
|
|
c = process_line(filename, line)
|
|
if c != None:
|
|
constants.append(c)
|
|
|
|
processed_file['constants'] = constants
|
|
|
|
return processed_file
|
|
|
|
def process_files():
|
|
seen_constants = []
|
|
processed_files = []
|
|
files = sorted(in_files, key=lambda d: d.split('/')[-1])
|
|
for f in files:
|
|
processed_files.append(process_file(f))
|
|
return processed_files
|
|
|
|
############################################################################
|
|
|
|
def build_constant(processed_constant):
|
|
constants = processed_constant
|
|
s = ''
|
|
|
|
is_enum = 'identifier' in processed_constant
|
|
if is_enum:
|
|
constants = processed_constant['constants']
|
|
else:
|
|
constants = [processed_constant]
|
|
|
|
for c in constants:
|
|
s += '%s = %s\n' % (c[0], c[1].replace('"', "'"))
|
|
|
|
return s
|
|
|
|
def build_file(processed_file):
|
|
s = ''
|
|
for c in processed_file['constants']:
|
|
s += build_constant(c)
|
|
|
|
return s
|
|
|
|
def build_files(processed_files):
|
|
s = ''
|
|
for file in processed_files:
|
|
s += build_file(file)
|
|
|
|
return s
|
|
|
|
def build_to_c(built_files):
|
|
txt = ''
|
|
with open(get_path(in_filename), 'r', newline='\n') as f:
|
|
txt = f.read()
|
|
txt += '\n' + built_files
|
|
|
|
while ('\n\n' in txt):
|
|
txt = txt.replace('\n\n', '\n')
|
|
|
|
lines = txt.splitlines()
|
|
txt = 'char gSmluaConstants[] = ""\n'
|
|
for line in lines:
|
|
txt += '"%s\\n"\n' % line
|
|
txt += ';'
|
|
return txt
|
|
|
|
############################################################################
|
|
|
|
def doc_constant_index(processed_files):
|
|
s = '# Supported Constants\n'
|
|
for processed_file in processed_files:
|
|
s += '- [%s](#%s)\n' % (processed_file['filename'], processed_file['filename'].replace('.', ''))
|
|
constants = [x for x in processed_file['constants'] if 'identifier' in x]
|
|
constants = sorted(constants, key=lambda d: d['identifier'])
|
|
for c in constants:
|
|
s += ' - [enum %s](#enum-%s)\n' % (c['identifier'], c['identifier'])
|
|
s += '\n<br />\n\n'
|
|
return s
|
|
|
|
def doc_constant(processed_constant):
|
|
constants = processed_constant
|
|
s = ''
|
|
|
|
is_enum = 'identifier' in processed_constant
|
|
if is_enum:
|
|
constants = processed_constant['constants']
|
|
if len(constants) == 0:
|
|
return ''
|
|
|
|
enum = 'enum ' + processed_constant['identifier']
|
|
s += '\n### [%s](#%s)\n' % (enum, processed_constant['identifier'])
|
|
s += '| Identifier | Value |\n'
|
|
s += '| :--------- | :---- |\n'
|
|
for c in constants:
|
|
s += '| %s | %s |\n' % (c[0], c[1])
|
|
return s
|
|
|
|
for c in [processed_constant]:
|
|
s += '- %s\n' % (c[0])
|
|
|
|
return s
|
|
|
|
def doc_file(processed_file):
|
|
s = '## [%s](#%s)\n' % (processed_file['filename'], processed_file['filename'])
|
|
constants = sorted(processed_file['constants'], key=lambda d: 'zzz' + d['identifier'] if 'identifier' in d else d[0])
|
|
for c in constants:
|
|
s += doc_constant(c)
|
|
|
|
s += '\n[:arrow_up_small:](#)\n'
|
|
s += '\n<br />\n\n'
|
|
return s
|
|
|
|
def doc_files(processed_files):
|
|
s = '## [:rewind: Lua Reference](lua.md)\n\n'
|
|
s += doc_constant_index(processed_files)
|
|
for file in processed_files:
|
|
s += doc_file(file)
|
|
|
|
return s
|
|
|
|
############################################################################
|
|
|
|
def def_constant(processed_constant):
|
|
constants = processed_constant
|
|
s = ''
|
|
|
|
is_enum = 'identifier' in processed_constant
|
|
if is_enum:
|
|
s += '\n--- @class %s\n' % translate_to_def(processed_constant['identifier'])
|
|
constants = processed_constant['constants']
|
|
if len(constants) == 0:
|
|
return ''
|
|
for c in constants:
|
|
s += '\n--- @type %s\n' % translate_to_def(processed_constant['identifier'])
|
|
s += '%s = %s\n' % (c[0], c[1])
|
|
return s
|
|
|
|
for c in [processed_constant]:
|
|
if '"' in c[1]:
|
|
s += '\n--- @type string\n'
|
|
else:
|
|
s += '\n--- @type integer\n'
|
|
s += '%s = %s\n' % (c[0], c[1])
|
|
|
|
return s
|
|
|
|
def build_to_def(processed_files):
|
|
s = '-- AUTOGENERATED FOR CODE EDITORS -- \n--- @meta\n--- @diagnostic disable\n\n'
|
|
with open(get_path(in_filename), 'r', newline='\n') as f:
|
|
s += f.read()
|
|
s += '\n'
|
|
|
|
for file in processed_files:
|
|
constants = sorted(file['constants'], key=lambda d: 'zzz' + d['identifier'] if 'identifier' in d else d[0])
|
|
for c in constants:
|
|
s += def_constant(c)
|
|
|
|
return s
|
|
|
|
############################################################################
|
|
|
|
def main():
|
|
processed_files = process_files()
|
|
built_files = build_files(processed_files)
|
|
validate_identifiers(built_files)
|
|
|
|
built_c = build_to_c(built_files)
|
|
|
|
with open(get_path(out_filename), 'w', newline='\n') as out:
|
|
out.write(built_c)
|
|
|
|
doc = doc_files(processed_files)
|
|
with open(get_path(out_filename_docs), 'w', newline='\n') as out:
|
|
out.write(doc)
|
|
|
|
defs = build_to_def(processed_files)
|
|
with open(get_path(out_filename_defs), 'w', newline='\n') as out:
|
|
out.write(defs)
|
|
|
|
global totalConstants
|
|
print("Total constants: " + str(totalConstants))
|
|
|
|
main()
|