diff --git a/scripts/headers/bw1_decomp_gen/generate_headers.py b/scripts/headers/bw1_decomp_gen/generate_headers.py index 2ff89ac..b7aa7b6 100644 --- a/scripts/headers/bw1_decomp_gen/generate_headers.py +++ b/scripts/headers/bw1_decomp_gen/generate_headers.py @@ -1,6 +1,8 @@ import time import shutil +import string import sys +from typing import Optional from clang import cindex from json import load from pathlib import Path @@ -153,23 +155,59 @@ def batched_arg_to_csnake(type_decls): ], remainder_functions) object_file_base_names = get_object_file_base_names() + object_file_base_names_lower = {str.lower(i): i for i in object_file_base_names} - def is_header_struct_name(type_name) -> bool: + def get_header_struct_name_key(type_name) -> Optional[str]: roomate_class_name = roomate_classes.get(type_name, type_name) if roomate_class_name[0] == 'G' and roomate_class_name[1].isupper(): roomate_class_name = roomate_class_name[1:] - if roomate_class_name in object_file_base_names: - return True - return False + result = object_file_base_names_lower.get(roomate_class_name.lower()) + if result is not None: + return result + if roomate_class_name[-1].lower() == 's': + result = object_file_base_names_lower.get(roomate_class_name[:-1].lower()) + if result is not None: + return result + return None def is_header_struct(data_type) -> bool: if type(data_type) is Struct and data_type.members and data_type.members[0].name in ["vftable", "super", "base"]: return True if type(data_type) is Struct or type(data_type) is Union: - if is_header_struct_name(data_type.name): + if get_header_struct_name_key(data_type.name) is not None: return True return False + def enum_name_to_potential_header_struct_name(type_name: str, num_stripped_suffixes) -> Optional[str]: + if type_name.count("_") < num_stripped_suffixes: + return None + if num_stripped_suffixes == 0: + if type_name in roomate_classes: + return roomate_classes[type_name] + return string.capwords(type_name).replace("_", "") + return "".join(map(string.capwords, type_name.split("_")[:-num_stripped_suffixes])) + + def get_enum_header_name_key(data_type) -> Optional[str]: + if type(data_type) is not Enum: + return None + + for num_stripped_suffixes in range(0, 3): + camels = list(filter(None, ( + enum_name_to_potential_header_struct_name(data_type.name, num_stripped_suffixes), + enum_name_to_potential_header_struct_name(data_type.name.removeprefix("LH_").removeprefix("LH").removesuffix("Enum").removesuffix("_t"), num_stripped_suffixes), + enum_name_to_potential_header_struct_name(f"LH_{data_type.name}", num_stripped_suffixes), + enum_name_to_potential_header_struct_name(f"LH3D_{data_type.name}", num_stripped_suffixes), + enum_name_to_potential_header_struct_name(data_type.name.replace("_TYPE", "_INFO"), num_stripped_suffixes), + enum_name_to_potential_header_struct_name(data_type.name.split("__")[0], num_stripped_suffixes), + ))) + if not camels: + break + for camel in camels: + header_name = get_header_struct_name_key(camel) + if header_name is not None: + return header_name + return None + def is_ignore_struct(data_type) -> bool: if type(data_type) is Struct or type(data_type) is Typedef: if data_type.name.startswith("RTTI"): @@ -185,7 +223,8 @@ def is_ignore_struct(data_type) -> bool: bases, vftable_function_prototypes, header_structs, - enums, + header_enums, + remainder_enums, lh_linked_pointer_lists, lh_linked_lists, lh_list_heads, @@ -199,11 +238,12 @@ def is_ignore_struct(data_type) -> bool: lambda x: type(x) is Union and x.name.endswith('Base'), lambda x: type(x) is FuncPtr and ('Vftable__' in x.name or x.name.startswith('vt_')), is_header_struct, + lambda x: type(x) is Enum and get_enum_header_name_key(x) is not None, lambda x: type(x) is Enum, lambda x: type(x) is Struct and x.name.startswith("LHLinkedList__p_") or x.name.startswith("LHLinkedNode__p_"), lambda x: type(x) is Struct and x.name.startswith("LHLinkedList__") or x.name.startswith("LHLinkedNode__"), lambda x: type(x) is Struct and x.name.startswith("LHListHead__"), - lambda x: type(x) is FuncPtr and "__" in x.name and is_header_struct_name(x.name[::-1].split("__")[-1][::-1]), + lambda x: type(x) is FuncPtr and "__" in x.name and get_header_struct_name_key(x.name[::-1].split("__")[-1][::-1]) is not None, is_ignore_struct, lambda x: type(x) is Struct, ], primitives) @@ -246,6 +286,14 @@ def get_path(name): local_header_import_map: dict[str, str] = {} header_map: dict[Path, Header] = {} + for e in header_enums: + path = get_path(get_enum_header_name_key(e)) + header = header_map.get(path) + structs: list[Struct] = header.structs if header is not None else [] + structs.append(e) + header = Header(path, [], structs) + header_map[path] = header + for t in member_function_pointers: struct_name = t.name[::-1].split("__")[-1][::-1] path = get_path(roomate_classes.get(struct_name, struct_name)) @@ -354,8 +402,9 @@ def get_path(name): print(f"Ignored {len(to_ignore)} entries") print(f"Took {toc - tic:0.4f} seconds") - if len(remainder_functions) + len(remainder_primitives) + len(remainder) > 0: + if len(remainder_functions) + len(remainder_primitives) + len(remainder_enums) + len(remainder) > 0: print(f"There are still {len(remainder_functions)} orphan functions: [{", ".join([i.name for i in remainder_functions][:10])}{", ..." if len(remainder_functions) > 10 else ""}]") print(f"There are still {len(remainder_primitives)} orphan structs: [{", ".join([i.name for i in remainder_primitives][:10])}{", ..." if len(remainder_primitives) > 10 else ""}]") + print(f"There are still {len(remainder_enums)} orphan enums: [{", ".join([i.name for i in remainder_enums][:10])}{", ..." if len(remainder_enums) > 10 else ""}]") print(f"There are still {len(remainder)} orphan entries: [{", ".join([i.name for i in remainder][:10])}{", ..." if len(remainder) > 10 else ""}]") exit(1) diff --git a/scripts/headers/bw1_decomp_gen/structs.py b/scripts/headers/bw1_decomp_gen/structs.py index 48ca02b..b5a5455 100644 --- a/scripts/headers/bw1_decomp_gen/structs.py +++ b/scripts/headers/bw1_decomp_gen/structs.py @@ -148,6 +148,10 @@ class Enum: def decorated_name(self): return f"enum {self.name}" + def get_types(self) -> set[str]: + result = {self.name} + return result + @classmethod def from_json(cls, decl: dict) -> "Enum": name = extract_type_name(decl['type']) @@ -158,7 +162,7 @@ def from_json(cls, decl: dict) -> "Enum": def to_csnake(self) -> csnake.Enum: result = csnake.Enum(self.name, typedef=False) for v in self.values: - result.add_variable(*v) + result.add_value(*v) return result def to_code(self, cw: csnake.CodeWriter): diff --git a/scripts/headers/bw1_decomp_gen/vanilla_filepaths.py b/scripts/headers/bw1_decomp_gen/vanilla_filepaths.py index 73ba5d9..569b989 100644 --- a/scripts/headers/bw1_decomp_gen/vanilla_filepaths.py +++ b/scripts/headers/bw1_decomp_gen/vanilla_filepaths.py @@ -564,6 +564,8 @@ BWPath(r"C:\dev\Libs\LIONHEAD\LHMultiplayer\VER4.0\LHPacket.h"), BWPath(r"C:\Dev\Libs\lionhead\lhlib\VER5.0\Name.h"), + BWPath(r"C:\Dev\Libs\lionhead\lhlib\VER5.0\LHKey.h"), + BWPath(r"C:\Dev\Libs\lionhead\lhlib\VER5.0\LHReturn.h"), BWPath(r"C:\Dev\Libs\lionhead\lhlib\VER5.0\Random.h"), BWPath(r"C:\DEV\LIBS\LHALL\RELEASED\HEADERS\VisitBlock.h"), @@ -630,6 +632,7 @@ BWPath(r"C:\Dev\black\DrawingObject.h"), BWPath(r"C:\Dev\black\EffectValues.h"), BWPath(r"C:\Dev\black\EarthQuake.h"), + BWPath(r"C:\Dev\black\Flower.h"), BWPath(r"C:\Dev\black\FixedObject.h"), BWPath(r"C:\Dev\black\FrontEnd.h"), BWPath(r"C:\Dev\black\AbodeInfo.h"), @@ -684,6 +687,8 @@ BWPath(r"C:\Dev\black\MobileWallHugInfo.h"), BWPath(r"C:\Dev\black\MultiMapFixedInfo.h"), BWPath(r"C:\Dev\black\ObjectInfo.h"), + BWPath(r"C:\Dev\black\PlaytimeInfo.h"), + BWPath(r"C:\Dev\black\Playtime.h"), BWPath(r"C:\Dev\black\PlayerInfo.h"), BWPath(r"C:\Dev\black\PrayerIconInfo.h"), BWPath(r"C:\Dev\black\PuzzleGame.h"), @@ -717,6 +722,7 @@ BWPath(r"C:\Dev\black\HandStateTotem.h"), BWPath(r"C:\Dev\black\HandStateTug.h"), BWPath(r"C:\Dev\black\HelpTextDataBase.h"), + BWPath(r"C:\Dev\black\HelpSpritesGuidance.h"), BWPath(r"C:\Dev\black\InnerCamera.h"), BWPath(r"C:\Dev\black\InterfaceHandState.h"), BWPath(r"C:\Dev\black\Landscape.h"), @@ -770,11 +776,13 @@ BWPath(r"C:\Dev\black\SpellSeedGraphic.h"), BWPath(r"C:\Dev\black\SpellWater.h"), BWPath(r"C:\Dev\black\SpellWithObjects.h"), + BWPath(r"C:\dev\black\SpookyVoicesInfo.h"), BWPath(r"C:\dev\Black\StandardBuildingSite.h"), BWPath(r"C:\Dev\black\StartGameBox.h"), BWPath(r"C:\Dev\black\StatsDatabase.h"), BWPath(r"C:\Dev\black\TerrainMapInfo.h"), BWPath(r"C:\Dev\black\TerrainMapTypeInfo.h"), + BWPath(r"C:\Dev\black\ToolTipsInfo.h"), BWPath(r"C:\Dev\black\TownCentreSpellIcon.h"), BWPath(r"C:\Dev\black\TownDesireFlags.h"), BWPath(r"C:\Dev\black\TownStats.h"), @@ -943,6 +951,56 @@ "LHJoypads": "LHJoypad", "FrameInfoLinkedList": "LHSystem", "LHConvert": "LHSystem", + "VORTEX_STAT_TYPE": "LandscapeVortex", + "VORTEX_STATE_TYPE": "LandscapeVortex", + "VORTEX_TYPE": "LandscapeVortex", + "RenderParticle": "PSysRenderParticle", + "PARTICLE_TYPE": "PSysInterface", + "HIGHLIGHT_INFO": "ScriptHighlight", + "RESOURCE_TYPE": "GameThing", + "FOOD_TYPE": "Object", + "SEX_TYPE": "Villager", + "CARRIED_OBJECT": "Villager", + "CARRIED_TREE_TYPE": "Villager", + "DEATH_REASON": "GameThingWithPos", + "DISCRETE_ALIGNMENT_VALUES": "Alignment", + "ObjectCircleIteratorDirection": "Collide", + "HOLD_TYPE": "Object", + "WALL_SECTION_TYPE": "MobileWallHug", + "MOVE_TO_STATES": "MobileWallHug", + "LEADER_ANIMATION": "GroupBehaviour", + "SEASON": "Weather", + "IMPRESSIVE_TYPE": "Reaction", + "DETECTED_PLAYER_ACTION": "Reaction", + "CAST_RULE_TYPE": "Spell", + "AUDIO_SFX_BANK_TYPE": "LHAudioSystem", + "LESSON_TYPE": "CreatureLessonChooser", + "SPEED_THRESHOLD": "Living", + "SPEED_MAX": "Living", + "SPEED_ID": "Living", + "TEXTJUSTIFY": "GatheringText", + "POWER_UP_TYPE": "TownArtifact", + "LANDED_TYPES": "Creature", + "MAGIC_LIVING_INFO": "SpecialVillager", + "GESTURE_TYPE": "GestureSystem", + "CREATURE_ISLES_BUILDINGS_INFO": "Abode", + "SOUND_COLLISION_TYPE": "SpookyVoicesInfo", + "SPOOKY_ENUM": "InterfaceCollide", + "DYK_CATEGORY": "ToolTipsInfo", + "IMMERSION_EFFECT_TYPE": "DialogBoxImmersion", + "TextureFormat_": "LH3DTexture", + "BBSTYLE": "SetupThing", + "CameraHelpReason": "CameraHelp", + "DETAIL_LEVEL": "LH3DRender", + "AnimInfoType": "LH3DAnim", + "LH_SEEK_MODE": "LHFile", + "LH_OPERATING_MODE": "LHLobby", + "LHKeyMod": "LHKey", + "GROUND_INFO": "Landscape", + "COUNTRY_LIST": "Landscape", + "VARIABLES": "Game", + "MISC_INFO": "Game", + "LOADER_VERSIONS": "PCMain", } unportable_dev_filepaths = released_filepaths_from_strings.union(guessed_filepaths)