diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 53af72694..59cdb164b 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1825,17 +1825,6 @@ def exportF3DtoC(dirPath, obj, DLFormat, transformMatrix, texDir, savePNG, texSe if DLFormat == DLFormat.Static: staticData.append(dynamicData) - else: - geoString = writeMaterialFiles( - dirPath, - modelDirPath, - '#include "actors/' + toAlnum(name) + '/header.h"', - '#include "actors/' + toAlnum(name) + '/material.inc.h"', - dynamicData.header, - dynamicData.source, - "", - True, - ) if texSeparate: texCFile = open(os.path.join(modelDirPath, "texture.inc.c"), "w", newline="\n") diff --git a/fast64_internal/sm64/animation/exporting.py b/fast64_internal/sm64/animation/exporting.py index 2ad37b5c7..1e8953691 100644 --- a/fast64_internal/sm64/animation/exporting.py +++ b/fast64_internal/sm64/animation/exporting.py @@ -15,8 +15,6 @@ encodeSegmentedAddr, decodeSegmentedAddr, get64bitAlignedAddr, - getPathAndLevel, - getExportDir, intToHex, applyBasicTweaks, toAlnum, @@ -34,6 +32,7 @@ update_actor_includes, int_from_str, write_or_delete_if_found, + get_export_dirs, ) from ..sm64_classes import BinaryExporter, RomReader, InsertableBinaryData from ..sm64_level_parser import parseLevelAtPointer @@ -433,6 +432,7 @@ def to_table_class( def update_includes( + sm64_props: "SM64_Properties", combined_props: "SM64_CombinedObjectProperties", header_dir: Path, actor_name, @@ -444,6 +444,7 @@ def update_includes( data_includes.append(Path("anims/table.inc.c")) header_includes.append(Path("anim_header.h")) update_actor_includes( + sm64_props, combined_props.export_header_type, combined_props.actor_group_name, header_dir, @@ -732,10 +733,11 @@ def export_animation_table_insertable(table: SM64_AnimTable, is_dma: bool, direc def create_and_get_paths( anim_props: "SM64_ArmatureAnimProperties", + sm64_props: "SM64_Properties", combined_props: "SM64_CombinedObjectProperties", actor_name: str, - decomp: Path, ): + decomp = sm64_props.abs_decomp_path anim_directory = geo_directory = header_directory = None if anim_props.is_dma: if combined_props.export_header_type == "Custom": @@ -744,13 +746,9 @@ def create_and_get_paths( else: anim_directory = Path(decomp, anim_props.dma_folder) else: - export_path, level_name = getPathAndLevel( - combined_props.is_actor_custom_export, - combined_props.actor_custom_path, - combined_props.export_level_name, - combined_props.level_name, - ) - header_directory, _tex_dir = getExportDir( + export_path, level_name = combined_props.get_path_and_level(sm64_props) + header_directory, _tex_dir = get_export_dirs( + sm64_props, combined_props.is_actor_custom_export, export_path, combined_props.export_header_type, @@ -770,16 +768,16 @@ def create_and_get_paths( def export_animation_table_c( anim_props: "SM64_ArmatureAnimProperties", + sm64_props: "SM64_Properties", combined_props: "SM64_CombinedObjectProperties", table: SM64_AnimTable, - decomp: Path, actor_name: str, - designated: bool, ): + designated = sm64_props.designated if not combined_props.is_actor_custom_export: - applyBasicTweaks(decomp) + applyBasicTweaks(sm64_props.abs_decomp_path) anim_directory, geo_directory, header_directory = create_and_get_paths( - anim_props, combined_props, actor_name, decomp + anim_props, sm64_props, combined_props, actor_name ) print("Creating all animation C data") @@ -815,7 +813,7 @@ def export_animation_table_c( enum_list_path=anim_directory / "table_enum.h", override_files=anim_props.override_files, ) - update_includes(combined_props, header_directory, actor_name, True) + update_includes(sm64_props, combined_props, header_directory, actor_name, True) def export_animation_binary( @@ -889,15 +887,15 @@ def export_animation_insertable(animation: SM64_Anim, is_dma: bool, directory: P def export_animation_c( animation: SM64_Anim, anim_props: "SM64_ArmatureAnimProperties", + sm64_props: "SM64_Properties", combined_props: "SM64_CombinedObjectProperties", - decomp: Path, actor_name: str, - designated: bool, ): + designated = sm64_props.designated if not combined_props.is_actor_custom_export: - applyBasicTweaks(decomp) + applyBasicTweaks(sm64_props.abs_decomp_path) anim_directory, geo_directory, header_directory = create_and_get_paths( - anim_props, combined_props, actor_name, decomp + anim_props, sm64_props, combined_props, actor_name ) (anim_directory / animation.file_name).write_text(animation.to_c(anim_props.is_dma)) @@ -956,9 +954,7 @@ def export_animation(context: Context, obj: Object): except Exception as exc: raise PluginError(f"Failed to generate animation class. {exc}") from exc if sm64_props.export_type == "C": - export_animation_c( - animation, anim_props, combined_props, sm64_props.abs_decomp_path, actor_name, sm64_props.designated - ) + export_animation_c(animation, anim_props, sm64_props, combined_props, actor_name) elif sm64_props.export_type == "Insertable Binary": export_animation_insertable(animation, anim_props.is_dma, Path(abspath(combined_props.insertable_directory))) elif sm64_props.export_type == "Binary": @@ -1011,9 +1007,7 @@ def export_animation_table(context: Context, obj: Object): print("Exporting table data") if sm64_props.export_type == "C": - export_animation_table_c( - anim_props, combined_props, table, sm64_props.abs_decomp_path, actor_name, sm64_props.designated - ) + export_animation_table_c(anim_props, sm64_props, combined_props, table, actor_name) elif sm64_props.export_type == "Insertable Binary": export_animation_table_insertable(table, anim_props.is_dma, Path(abspath(combined_props.insertable_directory))) elif sm64_props.export_type == "Binary": diff --git a/fast64_internal/sm64/animation/importing.py b/fast64_internal/sm64/animation/importing.py index c9d453546..510000d32 100644 --- a/fast64_internal/sm64/animation/importing.py +++ b/fast64_internal/sm64/animation/importing.py @@ -784,9 +784,18 @@ def update_table_preset(import_props: "SM64_AnimImportProperties", context): # If the previously selected animation isn't in this preset, select animation 0 import_props.preset_animation = "0" + sm64_props: SM64_Properties = context.scene.fast64.sm64 # C - decomp_path = import_props.decomp_path if import_props.decomp_path else context.scene.fast64.sm64.decomp_path - directory = preset.animation.directory if preset.animation.directory else f"{preset.decomp_path}/anims" + decomp_path = import_props.decomp_path if import_props.decomp_path else sm64_props.decomp_path + if preset.animation.dma: + directory = Path(sm64_props.vanilla_dma_anims_folder) + else: + if preset.typ == "ACTOR": + directory = Path(sm64_props.vanilla_actors_folder, preset.folder) + elif preset.typ == "LEVEL": + directory = Path(sm64_props.vanilla_levels_folder, preset.folder) + else: + raise ValueError(f"Unknown preset type {preset.typ}") import_props.path = os.path.join(decomp_path, directory) # Binary diff --git a/fast64_internal/sm64/settings/properties.py b/fast64_internal/sm64/settings/properties.py index cb9a57c5d..409e366dd 100644 --- a/fast64_internal/sm64/settings/properties.py +++ b/fast64_internal/sm64/settings/properties.py @@ -18,10 +18,12 @@ from ...utility import ( directory_path_checks, directory_ui_warnings, + draw_directory, prop_split, set_prop_if_in_data, upgrade_old_prop, get_first_set_prop, + draw_and_check_tab, ) from ..sm64_constants import defaultExtendSegment4, OLD_BINARY_LEVEL_ENUMS from ..sm64_objects import SM64_CombinedObjectProperties @@ -113,6 +115,16 @@ class SM64_Properties(PropertyGroup): description="Extremely recommended but must be off when compiling with IDO. Included in Repo Setting file", ) + folders_tab: BoolProperty(default=True, name="Export Folders") + actors_folder: StringProperty(name="Actors Folder", default="actors") + levels_folder: StringProperty(name="Levels Folder", default="levels") + dma_anims_folder: StringProperty(name="DMA Animations Folder", default="assets/anims") + + vanilla_folders_tab: BoolProperty(default=True, name="Vanilla Folders") + vanilla_actors_folder: StringProperty(name="Vanilla Actors Folder", default="actors") + vanilla_levels_folder: StringProperty(name="Vanilla Levels Folder", default="levels") + vanilla_dma_anims_folder: StringProperty(name="Vanilla DMA Animations Folder", default="assets/anims") + @property def binary_export(self): return self.export_type in {"Binary", "Insertable Binary"} @@ -207,6 +219,14 @@ def to_repo_settings(self): data["write_all"] = self.write_all if not self.hackersm64: data["designated"] = self.designated_prop + folders = {} + for is_vanilla in (False, True): + prefix = "vanilla_" if is_vanilla else "" + sub_categories = {} + for name in ("actors", "levels", "dma_anims"): + sub_categories[name] = getattr(self, f"{prefix}{name}_folder") + folders["vanilla" if is_vanilla else "export"] = sub_categories + data["folders"] = folders if self.custom_cmds: data["custom_cmds"] = [preset.to_dict("PRESET_EDIT") for preset in self.custom_cmds] return data @@ -219,6 +239,12 @@ def from_repo_settings(self, data: dict): set_prop_if_in_data(self, "lighting_engine_presets", data, "lighting_engine_presets") set_prop_if_in_data(self, "write_all", data, "write_all") set_prop_if_in_data(self, "designated_prop", data, "designated") + folders = data.get("folders", {}) + for is_vanilla in (False, True): + sub_categories = folders.get("vanilla" if is_vanilla else "export", {}) + prefix = "vanilla_" if is_vanilla else "" + for name in ("actors", "levels", "dma_anims"): + set_prop_if_in_data(self, f"{prefix}{name}_folder", sub_categories, name) if "custom_cmds" in data: self.custom_cmds.clear() for preset_data in data.get("custom_cmds", []): @@ -236,6 +262,23 @@ def draw_repo_settings(self, layout: UILayout): if self.matstack_fix: col.prop(self, "lighting_engine_presets") col.prop(self, "write_all") + for vanilla in (False, True): + prefix = "vanilla_" if vanilla else "" + if draw_and_check_tab(col, self, f"{prefix}folders_tab"): + name_prefix = "Vanilla" if vanilla else "" + draw_directory( + col, self, f"{prefix}actors_folder", name=f"{name_prefix} Actors", base_dir=self.abs_decomp_path + ) + draw_directory( + col, self, f"{prefix}levels_folder", name=f"{name_prefix} Levels", base_dir=self.abs_decomp_path + ) + draw_directory( + col, + self, + f"{prefix}dma_anims_folder", + name=f"{name_prefix} DMA Anims", + base_dir=self.abs_decomp_path, + ) draw_custom_cmd_presets(self, col.box()) def draw_props(self, layout: UILayout, show_repo_settings: bool = True): diff --git a/fast64_internal/sm64/sm64_collision.py b/fast64_internal/sm64/sm64_collision.py index d3982cc49..09c505deb 100644 --- a/fast64_internal/sm64/sm64_collision.py +++ b/fast64_internal/sm64/sm64_collision.py @@ -1,9 +1,22 @@ from pathlib import Path -import bpy, shutil, os, math, mathutils -from bpy.utils import register_class, unregister_class from io import BytesIO +import shutil +import os +import math +import typing + +import bpy +import mathutils +from bpy.utils import register_class, unregister_class + from .sm64_constants import insertableBinaryTypes, defaultExtendSegment4 -from .sm64_utility import export_rom_checks, to_include_descriptor, update_actor_includes, write_or_delete_if_found +from .sm64_utility import ( + export_rom_checks, + to_include_descriptor, + update_actor_includes, + write_or_delete_if_found, + get_export_dirs, +) from .sm64_objects import SM64_Area, start_process_sm64_objects from .sm64_level_parser import parse_level_binary from .sm64_rom_tweaks import ExtendBank0x04 @@ -17,12 +30,10 @@ encodeSegmentedAddr, get64bitAlignedAddr, prop_split, - getExportDir, duplicateHierarchy, cleanupDuplicatedObjects, writeInsertableFile, applyRotation, - getPathAndLevel, applyBasicTweaks, tempName, bytesToHex, @@ -30,6 +41,9 @@ selectSingleObject, ) +if typing.TYPE_CHECKING: + from .settings.properties import SM64_Properties + class CollisionVertex: def __init__(self, position): @@ -278,6 +292,7 @@ def exportCollisionBinary(obj, transformMatrix, romfile, startAddress, endAddres def exportCollisionC( + sm64_props: "SM64_Properties", obj, transformMatrix, dirPath, @@ -290,7 +305,7 @@ def exportCollisionC( groupName, levelName, ): - dirPath, texDir = getExportDir(customExport, dirPath, headerType, levelName, "", name) + dirPath, texDir = get_export_dirs(sm64_props, customExport, dirPath, headerType, levelName, "", name) name = toAlnum(name) colDirPath = os.path.join(dirPath, toAlnum(name)) @@ -324,7 +339,7 @@ def exportCollisionC( if writeRoomsFile: data_includes.append(Path("rooms.inc.c")) update_actor_includes( - headerType, groupName, Path(dirPath), name, levelName, data_includes, [Path("collision_header.h")] + sm64_props, headerType, groupName, Path(dirPath), name, levelName, data_includes, [Path("collision_header.h")] ) if not writeRoomsFile: # TODO: Could be done better if headerType == "Actor": @@ -335,7 +350,9 @@ def exportCollisionC( write_or_delete_if_found( group_path_c, to_remove=[ - to_include_descriptor(Path(name, "rooms.inc.c"), Path("levels", levelName, name, "rooms.inc.c")), + to_include_descriptor( + Path(name, "rooms.inc.c"), Path(sm64_props.levels_folder, levelName, name, "rooms.inc.c") + ), ], ) @@ -461,7 +478,8 @@ class SM64_ExportCollision(bpy.types.Operator): def execute(self, context): romfileOutput = None tempROM = None - props = context.scene.fast64.sm64.combined_export + sm64_props: SM64_Properties = context.scene.fast64.sm64 + props = sm64_props.combined_export try: obj = None if context.mode != "OBJECT": @@ -479,15 +497,11 @@ def execute(self, context): try: applyRotation([obj], math.radians(90), "X") if context.scene.fast64.sm64.export_type == "C": - export_path, level_name = getPathAndLevel( - props.is_actor_custom_export, - props.actor_custom_path, - props.export_level_name, - props.level_name, - ) + export_path, level_name = props.get_path_and_level(sm64_props) if not props.is_actor_custom_export: applyBasicTweaks(export_path) exportCollisionC( + sm64_props, obj, final_transform, export_path, diff --git a/fast64_internal/sm64/sm64_constants.py b/fast64_internal/sm64/sm64_constants.py index 11053ba82..a72bb4275 100644 --- a/fast64_internal/sm64/sm64_constants.py +++ b/fast64_internal/sm64/sm64_constants.py @@ -1,5 +1,5 @@ import dataclasses -from typing import Any, Iterable, TypeVar +from typing import Any, Iterable, Literal, TypeVar # RAM address used in evaluating switch for hatless Mario marioHatSwitch = 0x80277740 @@ -2289,7 +2289,6 @@ class AnimInfo: size: int | None = None # None means the size can be determined from the NULL delimiter ignore_bone_count: bool = False dma: bool = False - directory: str | None = None names: list[str] = dataclasses.field(default_factory=list) def __post_init__(self): @@ -2298,7 +2297,6 @@ def __post_init__(self): assert self.size is None or isinstance(self.size, int) assert isinstance(self.ignore_bone_count, bool) assert isinstance(self.dma, bool) - assert self.directory is None or isinstance(self.directory, str) assert validate_list(self.names, str) @@ -2348,7 +2346,8 @@ def __post_init__(self): @dataclasses.dataclass class ActorPresetInfo: - decomp_path: str = None + typ: Literal["ACTOR", "LEVEL"] = "ACTOR" + folder: str | None = None level: str | None = None group: str | None = None animation: DictOrVal[AnimInfo] = dataclasses.field(default_factory=dict) @@ -2356,7 +2355,8 @@ class ActorPresetInfo: collision: DictOrVal[CollisionInfo] = dataclasses.field(default_factory=dict) def __post_init__(self): - assert self.decomp_path is not None and isinstance(self.decomp_path, str) + assert self.typ in {"ACTOR", "LEVEL"} + assert self.folder is not None and isinstance(self.folder, str) assert self.group is None or isinstance(self.group, str) assert validate_dict(self.animation, AnimInfo) assert validate_dict(self.models, ModelInfo) @@ -2394,7 +2394,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): ACTOR_PRESET_INFO = { "Amp": ActorPresetInfo( - decomp_path="actors/amp", + folder="amp", group="common0", animation=AnimInfo( address=0x8004034, @@ -2405,7 +2405,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0xC2, "MODEL_AMP"), geolayout=0xF000028), ), "Bird": ActorPresetInfo( - decomp_path="actors/bird", + folder="bird", group="group10", animation=AnimInfo( address=0x50009E8, @@ -2415,19 +2415,19 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0x54, "MODEL_BIRDS"), geolayout=0xC000000), ), "Blargg": ActorPresetInfo( - decomp_path="actors/blargg", + folder="blargg", group="group2", animation=AnimInfo(address=0x500616C, names=["Idle", "Bite"]), models=ModelInfo(model_id=ModelIDInfo(0x54, "MODEL_BLARGG"), geolayout=0xC000240), ), "Blue Coin Switch": ActorPresetInfo( - decomp_path="actors/blue_coin_switch", + folder="blue_coin_switch", group="common0", models=ModelInfo(model_id=ModelIDInfo(0x8C, "MODEL_BLUE_COIN_SWITCH"), geolayout=0xF000000), collision=CollisionInfo(address=0x8000E98, c_name="blue_coin_switch_seg8_collision_08000E98"), ), "Blue Fish": ActorPresetInfo( - decomp_path="actors/blue_fish", + folder="blue_fish", group="common1", animation=AnimInfo(address=0x301C2B0, behaviours=0x13001B2C, names=["Swimming", "Diving"]), models={ @@ -2436,7 +2436,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Bobomb": ActorPresetInfo( - decomp_path="actors/bobomb", + folder="bobomb", group="common0", animation=AnimInfo( address=0x802396C, @@ -2449,7 +2449,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Bowser Bomb": ActorPresetInfo( - decomp_path="actors/bomb", + folder="bomb", group="group12", models=ModelInfo( model_id=[ModelIDInfo(0x65, "MODEL_BOWSER_BOMB_CHILD_OBJ"), ModelIDInfo(0xB3, "MODEL_BOWSER_BOMB")], @@ -2457,28 +2457,28 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): ), ), "Boo": ActorPresetInfo( - decomp_path="actors/boo", + folder="boo", group="group9", models=ModelInfo(model_id=ModelIDInfo(0x54, "MODEL_BOO"), geolayout=0xC000224), ), "Boo (Inside Castle)": ActorPresetInfo( - decomp_path="actors/boo_castle", + folder="boo_castle", group="group15", models=ModelInfo(model_id=ModelIDInfo(0x65, "MODEL_BOO_CASTLE"), geolayout=0xD0005B0), ), "Bookend": ActorPresetInfo( - decomp_path="actors/book", + folder="book", group="group9", models=ModelInfo(model_id=ModelIDInfo(0x59, "MODEL_BOOKEND"), geolayout=0xC0000C0), ), "Bookend Part": ActorPresetInfo( - decomp_path="actors/bookend", + folder="bookend", group="group9", animation=AnimInfo(address=0x5002540, behaviours=0x1300506C, names=["Opening Mouth", "Bite", "Closed"]), models=ModelInfo(model_id=ModelIDInfo(0x58, "MODEL_BOOKEND_PART"), geolayout=0xC000000), ), "Metal Ball": ActorPresetInfo( - decomp_path="actors/bowling_ball", + folder="bowling_ball", group="common0", models={ "Bowling Ball": ModelInfo(model_id=ModelIDInfo(0xB4, "MODEL_BOWLING_BALL"), geolayout=0xF000640), @@ -2488,7 +2488,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Bowser": ActorPresetInfo( - decomp_path="actors/bowser", + folder="bowser", group="group12", animation=AnimInfo( address=0x60577E0, @@ -2531,12 +2531,12 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Bowser Flame": ActorPresetInfo( - decomp_path="actors/bowser_flame", + folder="bowser_flame", group="group12", models=ModelInfo(model_id=ModelIDInfo(0x67, "MODEL_BOWSER_FLAMES"), geolayout=0xD000000), ), "Bowser Key": ActorPresetInfo( - decomp_path="actors/bowser_key", + folder="bowser_key", group="common1", animation=AnimInfo( address=0x30172D0, @@ -2552,7 +2552,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Breakable Box": ActorPresetInfo( - decomp_path="actors/breakable_box", + folder="breakable_box", group="common0", models={ "Breakable Box": ModelInfo(model_id=ModelIDInfo(0x81, "MODEL_BREAKABLE_BOX"), geolayout=0xF0005D0), @@ -2563,18 +2563,18 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): collision=CollisionInfo(address=0x8012D70, c_name="breakable_box_seg8_collision_08012D70"), ), "Bub": ActorPresetInfo( - decomp_path="actors/bub", + folder="bub", group="group13", animation=AnimInfo(address=0x6012354, behaviours=0x1300220C, names=["Swimming"]), models=ModelInfo(model_id=ModelIDInfo(0x64, "MODEL_BUB"), geolayout=0xD00038C), ), "Bubba": ActorPresetInfo( - decomp_path="actors/bubba", + folder="bubba", group="group11", models=ModelInfo(model_id=ModelIDInfo(0x59, "MODEL_BUBBA"), geolayout=0xC000000), ), "Bubble": ActorPresetInfo( - decomp_path="actors/bubble", + folder="bubble", group="group0", models={ "Bubble": ModelInfo(model_id=ModelIDInfo(0xA8, "MODEL_BUBBLE"), geolayout=0x17000000), @@ -2582,12 +2582,12 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Bullet Bill": ActorPresetInfo( - decomp_path="actors/bullet_bill", + folder="bullet_bill", group="group1", models=ModelInfo(model_id=ModelIDInfo(0x54, "MODEL_BULLET_BILL"), geolayout=0xC000264), ), "Bully": ActorPresetInfo( - decomp_path="actors/bully", + folder="bully", group="group2", animation=AnimInfo( address=0x500470C, @@ -2597,12 +2597,12 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0x56, "MODEL_BULLY"), geolayout=0xC000000), ), "Burn Smoke": ActorPresetInfo( - decomp_path="actors/burn_smoke", + folder="burn_smoke", group="group0", models=ModelInfo(model_id=ModelIDInfo(0x94, "MODEL_BURN_SMOKE"), geolayout=0x17000084), ), "Butterfly": ActorPresetInfo( - decomp_path="actors/butterfly", + folder="butterfly", group="common1", animation=AnimInfo( address=0x30056B0, @@ -2613,17 +2613,17 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0xBB, "MODEL_BUTTERFLY"), geolayout=0x160000A8), ), "Cannon Barrel": ActorPresetInfo( - decomp_path="actors/cannon_barrel", + folder="cannon_barrel", group="common0", models=ModelInfo(model_id=ModelIDInfo(0x7F, "MODEL_CANNON_BARREL"), geolayout=0xF0001C0), ), "Cannon Base": ActorPresetInfo( - decomp_path="actors/cannon_base", + folder="cannon_base", group="common0", models=ModelInfo(model_id=ModelIDInfo(0x80, "MODEL_CANNON_BASE"), geolayout=0xF0001A8), ), "Cannon Lid": ActorPresetInfo( - decomp_path="actors/cannon_lid", + folder="cannon_lid", group="common0", collision=CollisionInfo(address=0x8004950, c_name="cannon_lid_seg8_collision_08004950"), models=ModelInfo( @@ -2632,7 +2632,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): ), ), "Cap Switch": ActorPresetInfo( - decomp_path="actors/capswitch", + folder="capswitch", group="group8", models={ "Cap Switch": ModelInfo(model_id=ModelIDInfo(0x55, "MODEL_CAP_SWITCH"), geolayout=0xC000048), @@ -2651,30 +2651,30 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Chain Ball": ActorPresetInfo( # also known as metallic ball - decomp_path="actors/chain_ball", + folder="chain_ball", group="group14", models=ModelInfo(model_id=ModelIDInfo(0x65, "MODEL_METALLIC_BALL"), geolayout=0xD0005D0), ), "Chain Chomp": ActorPresetInfo( - decomp_path="actors/chain_chomp", + folder="chain_chomp", group="group14", animation=AnimInfo(address=0x6025178, behaviours=0x1300478C, names=["Chomping"]), models=ModelInfo(model_id=ModelIDInfo(0x66, "MODEL_CHAIN_CHOMP"), geolayout=0xD0005EC), ), "Haunted Chair": ActorPresetInfo( - decomp_path="actors/chair", + folder="chair", group="group9", animation=AnimInfo(address=0x5005784, behaviours=0x13004FD4, names=["Default Pose"]), models=ModelInfo(model_id=ModelIDInfo(0x56, "MODEL_HAUNTED_CHAIR"), geolayout=0xC0000D8), ), "Checkerboard Platform": ActorPresetInfo( - decomp_path="actors/checkerboard_platform", + folder="checkerboard_platform", group="common0", models=ModelInfo(model_id=ModelIDInfo(0xCA, "MODEL_CHECKERBOARD_PLATFORM"), geolayout=0xF0004E4), collision=CollisionInfo(address=0x800D710, c_name="checkerboard_platform_seg8_collision_0800D710"), ), "Chilly Chief": ActorPresetInfo( - decomp_path="actors/chilly_chief", + folder="chilly_chief", group="group16", animation=AnimInfo( address=0x6003994, @@ -2687,7 +2687,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Chuckya": ActorPresetInfo( - decomp_path="actors/chuckya", + folder="chuckya", group="common0", animation=AnimInfo( address=0x800C070, @@ -2697,13 +2697,13 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0xDF, "MODEL_CHUCKYA"), geolayout=0xF0001D8), ), "Clam Shell": ActorPresetInfo( - decomp_path="actors/clam", + folder="clam", group="group4", animation=AnimInfo(address=0x5001744, behaviours=0x13005440, names=["Close", "Open"]), models=ModelInfo(model_id=ModelIDInfo(0x58, "MODEL_CLAM_SHELL"), geolayout=0xC000000), ), "Coin": ActorPresetInfo( - decomp_path="actors/coin", + folder="coin", group="common1", models={ "Yellow Coin": ModelInfo(model_id=ModelIDInfo(0x74, "MODEL_YELLOW_COIN"), geolayout=0x1600013C), @@ -2721,13 +2721,13 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Cyan Fish": ActorPresetInfo( - decomp_path="actors/cyan_fish", + folder="cyan_fish", group="group13", animation=AnimInfo(address=0x600E264, names=["Swimming"]), models=ModelInfo(model_id=ModelIDInfo(0x67, "MODEL_CYAN_FISH"), geolayout=0xD000324), ), "Dirt": ActorPresetInfo( - decomp_path="actors/dirt", + folder="dirt", group="common1", models={ "Dirt": ModelInfo(model_id=ModelIDInfo(0x8A, "MODEL_DIRT_ANIMATION"), geolayout=0x16000ED4), @@ -2735,7 +2735,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Door": ActorPresetInfo( - decomp_path="actors/door", + folder="door", group="common1", animation=AnimInfo( address=0x30156C0, @@ -2792,7 +2792,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Dorrie": ActorPresetInfo( - decomp_path="actors/dorrie", + folder="dorrie", group="group17", animation=AnimInfo( address=0x600F638, behaviours=0x13004F90, size=3, names=["Idle", "Moving", "Lower and Raise Head"] @@ -2800,12 +2800,12 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0x68, "MODEL_DORRIE"), geolayout=0xD000230), ), "Exclamation Box": ActorPresetInfo( - decomp_path="actors/exclamation_box", + folder="exclamation_box", group="common0", models=ModelInfo(model_id=ModelIDInfo(0x89, "MODEL_EXCLAMATION_BOX"), geolayout=0xF000694), ), "Exclamation Box Outline": ActorPresetInfo( - decomp_path="actors/exclamation_box_outline", + folder="exclamation_box_outline", group="common0", models={ "Exclamation Box Outline": ModelInfo( @@ -2819,12 +2819,12 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): collision=CollisionInfo(address=0x8025F78, c_name="exclamation_box_outline_seg8_collision_08025F78"), ), "Explosion": ActorPresetInfo( - decomp_path="actors/explosion", + folder="explosion", group="common1", models=ModelInfo(model_id=ModelIDInfo(0xCD, "MODEL_EXPLOSION"), geolayout=0x16000040), ), "Eyerok": ActorPresetInfo( - decomp_path="actors/eyerok", + folder="eyerok", group="group5", animation=AnimInfo( address=0x50116E4, @@ -2837,7 +2837,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Flame": ActorPresetInfo( - decomp_path="actors/flame", + folder="flame", group="common1", models={ "Red Flame (With Shadow)": ModelInfo( @@ -2848,56 +2848,56 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Fly Guy": ActorPresetInfo( - decomp_path="actors/flyguy", + folder="flyguy", group="common0", animation=AnimInfo(address=0x8011A64, behaviours=0x130046DC, names=["Flying"]), models=ModelInfo(model_id=ModelIDInfo(0xDC, "MODEL_FLYGUY"), geolayout=0xF000518), ), "Fwoosh": ActorPresetInfo( - decomp_path="actors/fwoosh", + folder="fwoosh", group="group6", models=ModelInfo(model_id=ModelIDInfo(0x57, "MODEL_FWOOSH"), geolayout=0xC00036C), ), "Goomba": ActorPresetInfo( - decomp_path="actors/goomba", + folder="goomba", group="common0", animation=AnimInfo(address=0x801DA4C, behaviours=0x1300472C, names=["Walking"]), models=ModelInfo(model_id=ModelIDInfo(0xC0, "MODEL_GOOMBA"), geolayout=0xF0006E4), ), "Haunted Cage": ActorPresetInfo( - decomp_path="actors/haunted_cage", + folder="haunted_cage", group="group9", models=ModelInfo(model_id=ModelIDInfo(0x5A, "MODEL_HAUNTED_CAGE"), geolayout=0xC000274), ), "Heart": ActorPresetInfo( - decomp_path="actors/heart", + folder="heart", group="common0", models=ModelInfo(model_id=ModelIDInfo(0x78, "MODEL_HEART"), geolayout=0xF0004FC), ), "Heave-Ho": ActorPresetInfo( - decomp_path="actors/heave_ho", + folder="heave_ho", group="group1", animation=AnimInfo(address=0x501534C, behaviours=0x13001548, names=["Moving", "Throwing", "Stop"]), models=ModelInfo(model_id=ModelIDInfo(0x59, "MODEL_HEAVE_HO"), geolayout=0xC00028C), ), "Hoot": ActorPresetInfo( - decomp_path="actors/hoot", + folder="hoot", group="group1", animation=AnimInfo(address=0x5005768, behaviours=0x130033EC, names=["Flying", "Flying Fast"]), models=ModelInfo(model_id=ModelIDInfo(0x56, "MODEL_HOOT"), geolayout=0xC000018), ), "Bowser Impact Ring": ActorPresetInfo( - decomp_path="actors/impact_ring", + folder="impact_ring", group="group12", models=ModelInfo(model_id=ModelIDInfo(0x68, "MODEL_BOWSER_WAVE"), geolayout=0xD000090), ), "Bowser Impact Smoke": ActorPresetInfo( - decomp_path="actors/impact_smoke", + folder="impact_smoke", group="group12", models=ModelInfo(model_id=ModelIDInfo(0x66, "MODEL_BOWSER_SMOKE"), geolayout=0xD000BFC), ), "King Bobomb": ActorPresetInfo( - decomp_path="actors/bobomb", + folder="bobomb", group="group3", animation=AnimInfo( address=0x500FE30, @@ -2921,7 +2921,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0x56, "MODEL_KING_BOBOMB"), geolayout=0xC000000), ), "Klepto": ActorPresetInfo( - decomp_path="actors/klepto", + folder="klepto", group="group5", animation=AnimInfo( address=0x5008CFC, @@ -2940,7 +2940,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0x57, "MODEL_KLEPTO"), geolayout=0xC000000), ), "Koopa": ActorPresetInfo( - decomp_path="actors/koopa", + folder="koopa", group="group14", animation=AnimInfo( address=0x6011364, @@ -2970,13 +2970,13 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Koopa Flag": ActorPresetInfo( - decomp_path="actors/koopa_flag", + folder="koopa_flag", group="group14", animation=AnimInfo(address=0x6001028, behaviours=0x130045F8, names=["Waving"]), models=ModelInfo(model_id=ModelIDInfo(0x6A, "MODEL_KOOPA_FLAG"), geolayout=0xD000000), ), "Koopa Shell": ActorPresetInfo( - decomp_path="actors/koopa_shell", + folder="koopa_shell", group="common0", models={ "Koopa Shell": ModelInfo(model_id=ModelIDInfo(0xBE, "MODEL_KOOPA_SHELL"), geolayout=0xF000AB0), @@ -2985,7 +2985,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Lakitu (Cameraman)": ActorPresetInfo( - decomp_path="actors/lakitu_cameraman", + folder="lakitu_cameraman", group="group15", animation=AnimInfo( address=0x60058F8, @@ -2995,7 +2995,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0x66, "MODEL_LAKITU"), geolayout=0xD000000), ), "Lakitu (Enemy)": ActorPresetInfo( - decomp_path="actors/lakitu_enemy", + folder="lakitu_enemy", group="group11", animation=AnimInfo( address=0x50144D4, behaviours=0x13004918, names=["Flying", "No Spiny", "Throw Spiny", "Hold Spiny"] @@ -3003,29 +3003,28 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0x54, "MODEL_ENEMY_LAKITU"), geolayout=0xC0001BC), ), "Leaves": ActorPresetInfo( - decomp_path="actors/leaves", + folder="leaves", group="common1", models=ModelInfo(model_id=ModelIDInfo(0xA2, "MODEL_LEAVES"), geolayout=0x16000C8C), ), "Mad Piano": ActorPresetInfo( - decomp_path="actors/mad_piano", + folder="mad_piano", group="group9", animation=AnimInfo(address=0x5009B14, behaviours=0x13005024, names=["Sleeping", "Chomping"]), models=ModelInfo(model_id=ModelIDInfo(0x57, "MODEL_MAD_PIANO"), geolayout=0xC0001B4), ), "Manta Ray": ActorPresetInfo( - decomp_path="actors/manta", + folder="manta", group="group4", animation=AnimInfo(address=0x5008EB4, behaviours=0x13004370, names=["Swimming"]), models=ModelInfo(model_id=ModelIDInfo(0x54, "MODEL_MANTA_RAY"), geolayout=0x5008D14), ), "Mario": ActorPresetInfo( - decomp_path="actors/mario", + folder="mario", group="group0", animation=AnimInfo( address=0x4EC000, dma=True, - directory="assets/anims", names=[ "Slow ledge climb up", "Fall over backwards", @@ -3241,7 +3240,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0x1, "MODEL_MARIO"), geolayout=0x17002DD4), ), "Mario's Cap": ActorPresetInfo( - decomp_path="actors/mario_cap", + folder="mario_cap", group="common1", models={ "Mario's Cap": ModelInfo(model_id=ModelIDInfo(0x88, "MODEL_MARIOS_CAP"), geolayout=0x16000CA4), @@ -3253,7 +3252,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Metal Box": ActorPresetInfo( - decomp_path="actors/metal_box", + folder="metal_box", group="common0", models={ "Metal Box": ModelInfo(model_id=ModelIDInfo(0xD9, "MODEL_METAL_BOX"), geolayout=0xF000A30), @@ -3264,7 +3263,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): collision=CollisionInfo(address=0x8024C28, c_name="metal_box_seg8_collision_08024C28"), ), "Mips": ActorPresetInfo( - decomp_path="actors/mips", + folder="mips", group="group15", animation=AnimInfo( address=0x6015724, behaviours=0x130044FC, names=["Idle", "Hopping", "Thrown", "Thrown (Unused)", "Held"] @@ -3272,7 +3271,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0x64, "MODEL_MIPS"), geolayout=0xD000448), ), "Mist": ActorPresetInfo( - decomp_path="actors/mist", + folder="mist", group="common1", models={ "Mist": ModelInfo(model_id=ModelIDInfo(0x8E, "MODEL_MIST"), geolayout=0x16000000), @@ -3280,13 +3279,13 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Moneybag": ActorPresetInfo( - decomp_path="actors/moneybag", + folder="moneybag", group="group16", animation=AnimInfo(address=0x6005E5C, behaviours=0x130039A0, names=["Idle", "Prepare", "Jump", "Land", "Walk"]), models=ModelInfo(model_id=ModelIDInfo(0x66, "MODEL_MONEYBAG"), geolayout=0xD0000F0), ), "Monty Mole": ActorPresetInfo( - decomp_path="actors/monty_mole", + folder="monty_mole", group="group6", animation=AnimInfo( address=0x5007248, @@ -3307,7 +3306,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0x55, "MODEL_MONTY_MOLE"), geolayout=0xC000000), ), "Montey Mole Hole": ActorPresetInfo( - decomp_path="actors/monty_mole_hole", + folder="monty_mole_hole", group="group6", models=ModelInfo( model_id=ModelIDInfo(0x54, "MODEL_DL_MONTY_MOLE_HOLE"), @@ -3315,27 +3314,27 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): ), ), "Mr. I Eyeball": ActorPresetInfo( - decomp_path="actors/mr_i_eyeball", + folder="mr_i_eyeball", group="group16", models=ModelInfo(model_id=ModelIDInfo(0x67, "MODEL_MR_I"), geolayout=0xD000000), ), "Mr. I Iris": ActorPresetInfo( - decomp_path="actors/mr_i_iris", + folder="mr_i_iris", group="group16", models=ModelInfo(model_id=ModelIDInfo(0x66, "MODEL_MR_I_IRIS"), geolayout=0xD00001C), ), "Mushroom 1up": ActorPresetInfo( - decomp_path="actors/mushroom_1up", + folder="mushroom_1up", group="common1", models=ModelInfo(model_id=ModelIDInfo(0xD4, "MODEL_1UP"), geolayout=0x16000E84), ), "Orange Numbers": ActorPresetInfo( - decomp_path="actors/number", + folder="number", group="common1", models=ModelInfo(model_id=ModelIDInfo(0xDB, "MODEL_NUMBER"), geolayout=0x16000E14), ), "Peach": ActorPresetInfo( - decomp_path="actors/peach", + folder="peach", group="group10", animation=AnimInfo( address=0x501C504, @@ -3358,7 +3357,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0xDE, "MODEL_PEACH"), geolayout=0xC000410), ), "Pebble": ActorPresetInfo( - decomp_path="actors/pebble", + folder="pebble", group="common1", models=ModelInfo( model_id=ModelIDInfo(0xA1, "MODEL_PEBBLE"), @@ -3366,7 +3365,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): ), ), "Penguin": ActorPresetInfo( - decomp_path="actors/penguin", + folder="penguin", group="group7", animation=AnimInfo( address=0x5008B74, @@ -3383,7 +3382,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): collision=CollisionInfo(address=0x5008B88, c_name="penguin_seg5_collision_05008B88"), ), "Piranha Plant": ActorPresetInfo( - decomp_path="actors/piranha_plant", + folder="piranha_plant", group="group14", animation=AnimInfo( address=0x601C31C, @@ -3404,7 +3403,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0x64, "MODEL_PIRANHA_PLANT"), geolayout=0xD000358), ), "Pokey": ActorPresetInfo( - decomp_path="actors/pokey", + folder="pokey", group="group5", models={ "Pokey Head": ModelInfo(model_id=ModelIDInfo(0x54, "MODEL_POKEY_HEAD"), geolayout=0xC000610), @@ -3412,14 +3411,14 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Wooden Post": ActorPresetInfo( - decomp_path="actors/poundable_pole", + folder="poundable_pole", group="group14", models=ModelInfo(model_id=ModelIDInfo(0x6B, "MODEL_WOODEN_POST"), geolayout=0xD0000B8), collision=CollisionInfo(address=0x6002490, c_name="poundable_pole_collision_06002490"), ), # Should the power meter be included? "Power Meter": ActorPresetInfo( - decomp_path="actors/power_meter", + folder="power_meter", group="common1", models={ "Power Meter (Base)": ModelInfo(displaylist=DisplaylistInfo(0x3029480, "dl_power_meter_base")), @@ -3429,13 +3428,13 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Purple Switch": ActorPresetInfo( - decomp_path="actors/purple_switch", + folder="purple_switch", group="common0", models=ModelInfo(model_id=ModelIDInfo(0xCF, "MODEL_PURPLE_SWITCH"), geolayout=0xF0004CC), collision=CollisionInfo(address=0x800C7A8, c_name="purple_switch_seg8_collision_0800C7A8"), ), "Sand": ActorPresetInfo( - decomp_path="actors/sand", + folder="sand", group="common1", models=ModelInfo( model_id=ModelIDInfo(0x9F, "MODEL_SAND_DUST"), @@ -3443,19 +3442,19 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): ), ), "Scuttlebug": ActorPresetInfo( - decomp_path="actors/scuttlebug", + folder="scuttlebug", group="group17", animation=AnimInfo(address=0x6015064, behaviours=0x13002B5C, names=["Walking"]), models=ModelInfo(model_id=ModelIDInfo(0x65, "MODEL_SCUTTLEBUG"), geolayout=0xD000394), ), "Seaweed": ActorPresetInfo( - decomp_path="actors/seaweed", + folder="seaweed", group="group13", animation=AnimInfo(address=0x0600A4D4, behaviours=0x13003134, size=1, names=["Wave"]), models=ModelInfo(model_id=ModelIDInfo(0xC1, "MODEL_SEAWEED"), geolayout=0xD000284), ), "Skeeter": ActorPresetInfo( - decomp_path="actors/skeeter", + folder="skeeter", group="group13", animation=AnimInfo( address=0x6007DE0, behaviours=0x13005468, size=4, names=["Water Lunge", "Water Idle", "Walk", "Idle"] @@ -3463,17 +3462,17 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0x69, "MODEL_SKEETER"), geolayout=0xD000000), ), "(Beta) Boo Key": ActorPresetInfo( - decomp_path="actors/small_key", + folder="small_key", group="group9", models=ModelInfo(model_id=ModelIDInfo(0x55, "MODEL_BETA_BOO_KEY"), geolayout=0xC000188), ), "(Unused) Smoke": ActorPresetInfo( # TODO: double check - decomp_path="actors/smoke", + folder="smoke", group="group6", models=ModelInfo(displaylist=DisplaylistInfo(0x5007AF8, "smoke_seg5_dl_05007AF8")), ), "Mr. Blizzard": ActorPresetInfo( - decomp_path="actors/snowman", + folder="snowman", group="group7", animation=AnimInfo( address=0x500D118, behaviours={"Mr. Blizzard": 0x13004DBC}, names=["Spawn Snowball", "Throw Snowball"] @@ -3486,40 +3485,40 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Snufit": ActorPresetInfo( - decomp_path="actors/snufit", + folder="snufit", group="group17", models=ModelInfo(model_id=ModelIDInfo(0xCE, "MODEL_SNUFIT"), geolayout=0xD0001A0), ), "Sparkle": ActorPresetInfo( - decomp_path="actors/sparkle", + folder="sparkle", group="group0", models=ModelInfo(model_id=ModelIDInfo(0x95, "MODEL_SPARKLES"), geolayout=0x170001BC), ), "Sparkle Animation": ActorPresetInfo( - decomp_path="actors/sparkle_animation", + folder="sparkle_animation", group="group0", models=ModelInfo(model_id=ModelIDInfo(0x8F, "MODEL_SPARKLES_ANIMATION"), geolayout=0x17000284), ), "Spindrift": ActorPresetInfo( - decomp_path="actors/spindrift", + folder="spindrift", group="group7", animation=AnimInfo(address=0x5002D68, behaviours=0x130012B4, names=["Flying"]), models=ModelInfo(model_id=ModelIDInfo(0x54, "MODEL_SPINDRIFT"), geolayout=0xC000000), ), "Spiny": ActorPresetInfo( - decomp_path="actors/spiny", + folder="spiny", group="group11", animation=AnimInfo(address=0x5016EAC, behaviours={"Spiny": 0x130049C8}, names=["Walk"]), models=ModelInfo(model_id=ModelIDInfo(0x56, "MODEL_SPINY"), geolayout=0xC000328), ), "Spiny Egg": ActorPresetInfo( - decomp_path="actors/spiny_egg", + folder="spiny_egg", group="group11", animation=AnimInfo(address=0x50157E4, names=["Default"]), models=ModelInfo(model_id=ModelIDInfo(0x55, "MODEL_SPINY_BALL"), geolayout=0xC000290), ), "Springboard": ActorPresetInfo( - decomp_path="actors/springboard", + folder="springboard", group="group8", models={ "Springboard Top": ModelInfo(model_id=ModelIDInfo(0xB5, "MODEL_TRAMPOLINE"), geolayout=0xC000000), @@ -3528,12 +3527,12 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Star": ActorPresetInfo( - decomp_path="actors/star", + folder="star", group="common1", models=ModelInfo(model_id=ModelIDInfo(0x7A, "MODEL_STAR"), geolayout=0x16000EA0), ), "Small Water Splash": ActorPresetInfo( - decomp_path="actors/stomp_smoke", + folder="stomp_smoke", group="group0", models={ "Small Water Splash": ModelInfo( @@ -3543,24 +3542,24 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Sushi Shark": ActorPresetInfo( - decomp_path="actors/sushi", + folder="sushi", group="group4", animation=AnimInfo(address=0x500AE54, behaviours=0x13002338, size=1, names=["Swimming", "Diving"]), models=ModelInfo(model_id=ModelIDInfo(0x56, "MODEL_SUSHI"), geolayout=0xC000068), ), "Swoop": ActorPresetInfo( - decomp_path="actors/swoop", + folder="swoop", group="group17", animation=AnimInfo(address=0x60070D0, behaviours=0x13004698, size=2, names=["Idle", "Move"]), models=ModelInfo(model_id=ModelIDInfo(0x64, "MODEL_SWOOP"), geolayout=0xD0000DC), ), "Test Plataform": ActorPresetInfo( - decomp_path="actors/test_plataform", + folder="test_plataform", group="common0", collision=CollisionInfo(address=0x80262F8, c_name="unknown_seg8_collision_080262F8"), ), "Thwomp": ActorPresetInfo( - decomp_path="actors/thwomp", + folder="thwomp", group="group1", models=ModelInfo(model_id=ModelIDInfo(0x58, "MODEL_THWOMP"), geolayout=0xC000248), collision={ @@ -3569,7 +3568,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Toad": ActorPresetInfo( - decomp_path="actors/toad", + folder="toad", group="group15", animation=AnimInfo( address=0x600FC48, @@ -3589,17 +3588,17 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0xDD, "MODEL_TOAD"), geolayout=0xD0003E4), ), "Tweester/Tornado": ActorPresetInfo( - decomp_path="actors/tornado", + folder="tornado", group="group5", models=ModelInfo(model_id=ModelIDInfo(0x56, "MODEL_TWEESTER"), geolayout=0x5014630), ), "Transparent Star": ActorPresetInfo( - decomp_path="actors/transperant_star", + folder="transperant_star", group="common1", models=ModelInfo(model_id=ModelIDInfo(0x79, "MODEL_TRANSPARENT_STAR"), geolayout=0x16000F6C), ), "Treasure Chest": ActorPresetInfo( - decomp_path="actors/treasure_chest", + folder="treasure_chest", group="group13", models={ "Treasure Chest Base": ModelInfo( @@ -3611,7 +3610,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Tree": ActorPresetInfo( - decomp_path="actors/tree", + folder="tree", group="common1", models={ "Bubbly Tree": ModelInfo( @@ -3634,7 +3633,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Ukiki": ActorPresetInfo( - decomp_path="actors/ukiki", + folder="ukiki", group="group6", animation=AnimInfo( address=0x5015784, @@ -3658,7 +3657,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0x56, "MODEL_UKIKI"), geolayout=0xC000110), ), "Unagi": ActorPresetInfo( - decomp_path="actors/unagi", + folder="unagi", group="group4", animation=AnimInfo( address=0x5012824, @@ -3669,12 +3668,12 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0x55, "MODEL_UNAGI"), geolayout=0xC00010C), ), "Smoke": ActorPresetInfo( - decomp_path="actors/walk_smoke", + folder="walk_smoke", group="group0", models=ModelInfo(model_id=ModelIDInfo(0x96, "MODEL_SMOKE"), geolayout=0x17000038), ), "Warp Collision": ActorPresetInfo( - decomp_path="actors/warp_collision", + folder="warp_collision", group="common1", collision={ "Door": CollisionInfo(address=0x301CE78, c_name="door_seg3_collision_0301CE78"), @@ -3682,7 +3681,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Warp Pipe": ActorPresetInfo( - decomp_path="actors/warp_pipe", + folder="warp_pipe", group="common1", models=ModelInfo( model_id=[ @@ -3696,7 +3695,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): ), ), "Water Bomb": ActorPresetInfo( - decomp_path="actors/water_bubble", + folder="water_bubble", group="group3", models={ "Water Bomb": ModelInfo(model_id=ModelIDInfo(0x54, "MODEL_WATER_BOMB"), geolayout=0xC000308), @@ -3706,12 +3705,12 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Water Mine": ActorPresetInfo( - decomp_path="actors/water_mine", + folder="water_mine", group="group13", models=ModelInfo(model_id=ModelIDInfo(0xB3, "MODEL_WATER_MINE"), geolayout=0xD0002F4), ), "Water Ring": ActorPresetInfo( - decomp_path="actors/water_ring", + folder="water_ring", group="group13", animation=AnimInfo( address=0x6013F7C, @@ -3721,12 +3720,12 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): models=ModelInfo(model_id=ModelIDInfo(0x68, "MODEL_WATER_RING"), geolayout=0xD000414), ), "Water Splash": ActorPresetInfo( - decomp_path="actors/water_splash", + folder="water_splash", group="group0", models=ModelInfo(model_id=ModelIDInfo(0xA7, "MODEL_WATER_SPLASH"), geolayout=0x17000230), ), "Water Wave": ActorPresetInfo( - decomp_path="actors/water_wave", + folder="water_wave", group="group0", models={ "Idle Water Wave": ModelInfo(model_id=ModelIDInfo(0xA6, "MODEL_IDLE_WATER_WAVE"), geolayout=0x17000124), @@ -3734,7 +3733,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Whirlpool": ActorPresetInfo( - decomp_path="actors/whirlpool", + folder="whirlpool", group="group4", models=ModelInfo( model_id=ModelIDInfo(0x57, "MODEL_DL_WHIRLPOOL"), @@ -3742,7 +3741,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): ), ), "White Particle": ActorPresetInfo( - decomp_path="actors/white_particle", + folder="white_particle", group="common1", models={ "White Particle": ModelInfo(model_id=ModelIDInfo(0xA0, "MODEL_WHITE_PARTICLE"), geolayout=0x16000F98), @@ -3753,7 +3752,7 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "White Particle Small": ActorPresetInfo( - decomp_path="actors/white_particle_small", + folder="white_particle_small", group="group0", models={ "White Particle Small": ModelInfo( @@ -3766,53 +3765,54 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): }, ), "Whomp": ActorPresetInfo( - decomp_path="actors/whomp", + folder="whomp", group="group14", animation=AnimInfo(address=0x6020A04, behaviours=0x13002BCC, size=2, names=["Walk", "Jump"]), models=ModelInfo(model_id=ModelIDInfo(0x67, "MODEL_WHOMP"), geolayout=0xD000480), collision=CollisionInfo(address=0x6020A0C, c_name="whomp_seg6_collision_06020A0C"), ), "Wiggler Body": ActorPresetInfo( - decomp_path="actors/wiggler_body", + folder="wiggler_body", group="group11", animation=AnimInfo(address=0x500C874, behaviours=0x130048E0, size=1, names=["Walk"]), models=ModelInfo(model_id=ModelIDInfo(0x58, "MODEL_WIGGLER_BODY"), geolayout=0x500C778), ), "Wiggler Head": ActorPresetInfo( - decomp_path="actors/wiggler_head", + folder="wiggler_head", group="group11", animation=AnimInfo(address=0x500EC8C, behaviours=0x13004898, size=1, names=["Walk"]), models=ModelInfo(model_id=ModelIDInfo(0x57, "MODEL_WIGGLER_HEAD"), geolayout=0xC000030), ), "Wooden Signpost": ActorPresetInfo( - decomp_path="actors/wooden_signpost", + folder="wooden_signpost", group="common1", models=ModelInfo(model_id=ModelIDInfo(0x7C, "MODEL_WOODEN_SIGNPOST"), geolayout=0x16000FB4), collision=CollisionInfo(address=0x302DD80, c_name="wooden_signpost_seg3_collision_0302DD80"), ), "Yellow Sphere (Bowser 1)": ActorPresetInfo( - decomp_path="actors/yellow_sphere", + folder="yellow_sphere", group="group12", models=ModelInfo(model_id=ModelIDInfo(0x3, "MODEL_LEVEL_GEOMETRY_03"), geolayout=0xD0000B0), ), "Yellow Sphere": ActorPresetInfo( - decomp_path="actors/yellow_sphere_small", + folder="yellow_sphere_small", group="group1", models=ModelInfo(model_id=ModelIDInfo(0x55, "MODEL_YELLOW_SPHERE"), geolayout=0xC000000), ), "Yoshi": ActorPresetInfo( - decomp_path="actors/yoshi", + folder="yoshi", group="group10", animation=AnimInfo(address=0x50241E8, behaviours=0x13004538, names=["Idle", "Walk", "Jump"]), models=ModelInfo(model_id=ModelIDInfo(0x55, "MODEL_YOSHI"), geolayout=0xC000468), ), "(Unused) Yoshi Egg": ActorPresetInfo( - decomp_path="actors/yoshi_egg", + folder="yoshi_egg", group="group1", models=ModelInfo(model_id=ModelIDInfo(0x57, "MODEL_YOSHI_EGG"), geolayout=0xC0001E4), ), "Castle Flag": ActorPresetInfo( - decomp_path="levels/castle_grounds/areas/1/11", + typ="LEVEL", + folder="castle_grounds/areas/1/11", level="CG", animation=AnimInfo(address=0x700C95C, behaviours=0x13003C58, size=1, names=["Wave"]), models=ModelInfo(model_id=ModelIDInfo(0x37, "MODEL_CASTLE_GROUNDS_FLAG"), geolayout=0xE000660), diff --git a/fast64_internal/sm64/sm64_f3d_writer.py b/fast64_internal/sm64/sm64_f3d_writer.py index 1aad38346..6c59a37e9 100644 --- a/fast64_internal/sm64/sm64_f3d_writer.py +++ b/fast64_internal/sm64/sm64_f3d_writer.py @@ -1,9 +1,16 @@ from pathlib import Path -import shutil, copy, bpy, re, os +from math import radians from io import BytesIO -from math import ceil, log, radians +from typing import Tuple, TYPE_CHECKING +import shutil +import copy +import re +import os + +import bpy from mathutils import Matrix, Vector from bpy.utils import register_class, unregister_class + from ..panels import SM64_Panel from ..f3d.f3d_writer import exportF3DCommon, saveModeSetting from ..f3d.f3d_texture_writer import TexInfo @@ -23,11 +30,11 @@ update_actor_includes, write_or_delete_if_found, write_material_headers, + draw_export_dir, + get_export_dirs, ) from .sm64_level_parser import parse_level_binary from .sm64_rom_tweaks import ExtendBank0x04 -from typing import Tuple - from ..f3d.f3d_bleed import BleedGraphics from ..f3d.f3d_gbi import ( @@ -71,11 +78,9 @@ toAlnum, checkIfPathExists, overwriteData, - getExportDir, writeMaterialFiles, get64bitAlignedAddr, writeInsertableFile, - getPathAndLevel, applyBasicTweaks, tempName, getAddressFromRAMAddress, @@ -83,12 +88,14 @@ customExportWarning, decompFolderMessage, makeWriteInfoBox, - writeBoxExportType, create_or_get_world, + as_posix, ) from .sm64_constants import defaultExtendSegment4, bank0Segment, insertableBinaryTypes +if TYPE_CHECKING: + from .settings.properties import SM64_Properties enumHUDExportLocation = [ ("HUD", "HUD", "Exports to src/game/hud.c"), @@ -349,6 +356,7 @@ def exportTexRectCommon(texProp, name, convertTextureData): def sm64ExportF3DtoC( + sm64_props: "SM64_Properties", basePath, obj, DLFormat, @@ -363,7 +371,8 @@ def sm64ExportF3DtoC( customExport, headerType, ): - dirPath, texDir = getExportDir(customExport, basePath, headerType, levelName, texDir, name) + name = toAlnum(name) or "" + dirPath, texDir = get_export_dirs(sm64_props, customExport, basePath, headerType, levelName, texDir, name) inline = bpy.context.scene.exportInlineF3D fModel = SM64Model( @@ -377,7 +386,7 @@ def sm64ExportF3DtoC( bleed_gfx = BleedGraphics() bleed_gfx.bleed_fModel(fModel, fMeshes) - modelDirPath = os.path.join(dirPath, toAlnum(name)) + modelDirPath = os.path.join(dirPath, name) if not os.path.exists(modelDirPath): os.mkdir(modelDirPath) @@ -398,14 +407,21 @@ def sm64ExportF3DtoC( scrollData = fModel.to_c_scroll(scrollName, gfxFormatter) modifyTexScrollFiles(basePath, modelDirPath, scrollData) + if headerType == "Actor": + actor_folder = Path(sm64_props.actors_folder, name) + elif headerType == "Level": + actor_folder = Path(sm64_props.levels_folder, levelName, name) + else: + actor_folder = Path(name) + if DLFormat == DLFormat.Static: staticData.append(dynamicData) else: geoString = writeMaterialFiles( basePath, modelDirPath, - '#include "actors/' + toAlnum(name) + '/header.h"', - '#include "actors/' + toAlnum(name) + '/material.inc.h"', + f'#include "{as_posix(actor_folder / "header.h")}', + f'#include "{as_posix(actor_folder / "material.inc.h")}"', dynamicData.header, dynamicData.source, "", @@ -428,37 +444,29 @@ def sm64ExportF3DtoC( cDefFile.close() update_actor_includes( - headerType, groupName, Path(dirPath), name, levelName, [Path("model.inc.c")], [Path("header.h")] + sm64_props, headerType, groupName, Path(dirPath), name, levelName, [Path("model.inc.c")], [Path("header.h")] ) fileStatus = None if not customExport: if headerType == "Actor": if DLFormat != DLFormat.Static: # Change this - write_material_headers( - Path(basePath), - Path("actors", toAlnum(name), "material.inc.c"), - Path("actors", toAlnum(name), "material.inc.h"), - ) + write_material_headers(Path(basePath), actor_folder / "material.inc.c", actor_folder / "material.inc.h") - texscrollIncludeC = '#include "actors/' + name + '/texscroll.inc.c"' - texscrollIncludeH = '#include "actors/' + name + '/texscroll.inc.h"' texscrollGroup = groupName - texscrollGroupInclude = '#include "actors/' + groupName + '.h"' + texscrollGroupInclude = f'#include "{as_posix(Path(sm64_props.actors_folder, f"{groupName}.h"))}"' elif headerType == "Level": if DLFormat != DLFormat.Static: # Change this - write_material_headers( - basePath, - Path("actors", levelName, toAlnum(name), "material.inc.c"), - Path("actors", levelName, toAlnum(name), "material.inc.h"), - ) + write_material_headers(basePath, actor_folder / "material.inc.c", actor_folder / "material.inc.h") - texscrollIncludeC = '#include "levels/' + levelName + "/" + name + '/texscroll.inc.c"' - texscrollIncludeH = '#include "levels/' + levelName + "/" + name + '/texscroll.inc.h"' texscrollGroup = levelName - texscrollGroupInclude = '#include "levels/' + levelName + '/header.h"' - + texscrollGroupInclude = f'#include "{as_posix(Path(sm64_props.levels_folder, levelName, "header.h"))}"' + else: + raise PluginError(f"Unknown header type: {headerType}") + include_c, include_h = actor_folder / "texscroll.inc.c", actor_folder / "texscroll.inc.h" + texscrollIncludeC, texscrollIncludeH = f'#include "{as_posix(include_c)}"', f'#include "{as_posix(include_h)}"' fileStatus = modifyTexScrollHeadersGroup( + sm64_props, basePath, texscrollIncludeC, texscrollIncludeH, @@ -577,7 +585,8 @@ class SM64_ExportDL(bpy.types.Operator): def execute(self, context): romfileOutput = None tempROM = None - props = context.scene.fast64.sm64.combined_export + sm64_props: SM64_Properties = context.scene.fast64.sm64 + props = sm64_props.combined_export try: if context.mode != "OBJECT": raise PluginError("Operator can only be used in object mode.") @@ -598,15 +607,11 @@ def execute(self, context): try: applyRotation([obj], radians(90), "X") if context.scene.fast64.sm64.export_type == "C": - exportPath, levelName = getPathAndLevel( - props.is_actor_custom_export, - props.actor_custom_path, - props.export_level_name, - props.level_name, - ) + exportPath, levelName = props.get_path_and_level(sm64_props) if not props.is_actor_custom_export: applyBasicTweaks(exportPath) fileStatus = sm64ExportF3DtoC( + sm64_props, exportPath, obj, DLFormat.Static if context.scene.DLExportisStatic else DLFormat.Dynamic, @@ -722,9 +727,10 @@ class SM64_ExportDLPanel(SM64_Panel): def draw(self, context): col = self.layout.column() propsDLE = col.operator(SM64_ExportDL.bl_idname) - props = context.scene.fast64.sm64.combined_export + sm64_props: SM64_Properties = context.scene.fast64.sm64 + props = sm64_props.combined_export - if context.scene.fast64.sm64.export_type == "C": + if sm64_props.export_type == "C": col.prop(context.scene, "DLExportisStatic") prop_split(col, props, "export_header_type", "Export Type") @@ -749,15 +755,16 @@ def draw(self, context): decompFolderMessage(col) writeBox = makeWriteInfoBox(col) - writeBoxExportType( + draw_export_dir( writeBox, + sm64_props, props.export_header_type, context.scene.DLName, props.export_level_name, props.level_name, ) - elif context.scene.fast64.sm64.export_type == "Insertable Binary": + elif sm64_props.export_type == "Insertable Binary": col.prop(context.scene, "DLInsertableBinaryPath") else: prop_split(col, context.scene, "DLExportStart", "Start Address") diff --git a/fast64_internal/sm64/sm64_geolayout_writer.py b/fast64_internal/sm64/sm64_geolayout_writer.py index f51edea0b..42c61361e 100644 --- a/fast64_internal/sm64/sm64_geolayout_writer.py +++ b/fast64_internal/sm64/sm64_geolayout_writer.py @@ -1,10 +1,17 @@ from __future__ import annotations from pathlib import Path +from io import BytesIO import typing +import math +import copy +import os +import shutil +import re + +import bpy +import mathutils -import bpy, mathutils, math, copy, os, shutil, re from bpy.utils import register_class, unregister_class -from io import BytesIO from ..operators import ObjectDataExporter from ..panels import SM64_Panel @@ -15,7 +22,13 @@ from .sm64_texscroll import modifyTexScrollFiles, modifyTexScrollHeadersGroup from .sm64_level_parser import parse_level_binary from .sm64_rom_tweaks import ExtendBank0x04 -from .sm64_utility import export_rom_checks, starSelectWarning, update_actor_includes, write_material_headers +from .sm64_utility import ( + export_rom_checks, + starSelectWarning, + update_actor_includes, + write_material_headers, + get_export_dirs, +) from ..utility import ( PluginError, @@ -26,7 +39,6 @@ findStartBones, duplicateHierarchy, cleanupDuplicatedObjects, - getExportDir, toAlnum, writeMaterialFiles, get64bitAlignedAddr, @@ -47,7 +59,6 @@ getFMeshName, checkUniqueBoneNames, applyRotation, - getPathAndLevel, applyBasicTweaks, tempName, getAddressFromRAMAddress, @@ -55,6 +66,7 @@ geoNodeRotateOrder, deselectAllObjects, selectSingleObject, + as_posix, ) from ..f3d.f3d_bleed import ( @@ -127,6 +139,7 @@ if typing.TYPE_CHECKING: from .sm64_geolayout_bone import SM64_BoneProperties + from .settings.properties import SM64_Properties def get_custom_cmd_with_transform(node: "CustomNode", parentTransformNode, translate, rotate): @@ -458,7 +471,7 @@ def add_overrides_to_fmodel(f_model: SM64Model): def convertArmatureToGeolayout(armatureObj, obj, convertTransformMatrix, camera, name, DLFormat, convertTextureData): inline = bpy.context.scene.exportInlineF3D fModel = SM64Model( - name, + toAlnum(name), DLFormat, bpy.context.scene.fast64.sm64.gfx_write_method, ) @@ -534,7 +547,7 @@ def convertObjectToGeolayout( inline = bpy.context.scene.exportInlineF3D if fModel is None: fModel = SM64Model( - name, + toAlnum(name), DLFormat, bpy.context.scene.fast64.sm64.gfx_write_method, ) @@ -603,6 +616,7 @@ def convertObjectToGeolayout( # C Export def exportGeolayoutArmatureC( + sm64_props: "SM64_Properties", armatureObj, obj, convertTransformMatrix, @@ -624,6 +638,7 @@ def exportGeolayoutArmatureC( ) return saveGeolayoutC( + sm64_props, geoName, dirName, geolayoutGraph, @@ -641,6 +656,7 @@ def exportGeolayoutArmatureC( def exportGeolayoutObjectC( + sm64_props: "SM64_Properties", obj, convertTransformMatrix, dirPath, @@ -660,6 +676,7 @@ def exportGeolayoutObjectC( ) return saveGeolayoutC( + sm64_props, geoName, dirName, geolayoutGraph, @@ -677,6 +694,7 @@ def exportGeolayoutObjectC( def saveGeolayoutC( + sm64_props: "SM64_Properties", geoName, dirName, geolayoutGraph: GeolayoutGraph, @@ -691,7 +709,7 @@ def saveGeolayoutC( customExport, DLFormat, ): - dirPath, texDir = getExportDir(customExport, exportDir, headerType, levelName, texDir, dirName) + dirPath, texDir = get_export_dirs(sm64_props, customExport, exportDir, headerType, levelName, texDir, dirName) dirName = toAlnum(dirName) groupName = toAlnum(groupName) @@ -736,13 +754,14 @@ def saveGeolayoutC( geoData = geolayoutGraph.to_c() if headerType == "Actor": - matCInclude = Path("actors", dirName, "material.inc.c") - matHInclude = Path("actors", dirName, "material.inc.h") - headerInclude = '#include "actors/' + dirName + '/geo_header.h"' + actor_folder = Path(sm64_props.actors_folder, dirName) + elif headerType == "Level": + actor_folder = Path(sm64_props.levels_folder, levelName, dirName) else: - matCInclude = Path("levels", levelName, dirName, "material.inc.c") - matHInclude = Path("levels", levelName, dirName, "material.inc.h") - headerInclude = '#include "levels/' + levelName + "/" + dirName + '/geo_header.h"' + actor_folder = Path(dirName) + matCInclude = actor_folder / "material.inc.c" + matHInclude = actor_folder / "material.inc.h" + headerInclude = f'#include "{as_posix(actor_folder / "geo_header.h")}"' modifyTexScrollFiles(exportDir, geoDirPath, scrollData) @@ -788,6 +807,7 @@ def saveGeolayoutC( fileStatus = None update_actor_includes( + sm64_props, headerType, groupName, Path(dirPath), @@ -848,18 +868,19 @@ def saveGeolayoutC( appendSecondaryGeolayout(geoDirPath, 'bully', 'bully_boss', 'GEO_SCALE(0x00, 0x2000), GEO_NODE_OPEN(),') """ - texscrollIncludeC = '#include "actors/' + dirName + '/texscroll.inc.c"' - texscrollIncludeH = '#include "actors/' + dirName + '/texscroll.inc.h"' texscrollGroup = groupName - texscrollGroupInclude = '#include "actors/' + groupName + '.h"' + texscrollGroupInclude = f'#include "{as_posix(Path(sm64_props.actors_folder, f"{groupName}.h"))}"' elif headerType == "Level": - texscrollIncludeC = '#include "levels/' + levelName + "/" + dirName + '/texscroll.inc.c"' - texscrollIncludeH = '#include "levels/' + levelName + "/" + dirName + '/texscroll.inc.h"' texscrollGroup = levelName - texscrollGroupInclude = '#include "levels/' + levelName + '/header.h"' + texscrollGroupInclude = f'#include "{as_posix(Path(sm64_props.levels_folder, levelName, "header.h"))}"' + else: + raise PluginError(f"Unknown header type: {headerType}") + include_c, include_h = actor_folder / "texscroll.inc.c", actor_folder / "texscroll.inc.h" + texscrollIncludeC, texscrollIncludeH = f'#include "{as_posix(include_c)}"', f'#include "{as_posix(include_h)}"' fileStatus = modifyTexScrollHeadersGroup( + sm64_props, exportDir, texscrollIncludeC, texscrollIncludeH, @@ -2870,7 +2891,8 @@ class SM64_ExportGeolayoutObject(ObjectDataExporter): def execute(self, context): romfileOutput = None tempROM = None - props = context.scene.fast64.sm64.combined_export + sm64_props: SM64_Properties = context.scene.fast64.sm64 + props = sm64_props.combined_export try: obj = None if context.mode != "OBJECT": @@ -2897,15 +2919,11 @@ def execute(self, context): save_textures = bpy.context.scene.saveTextures if context.scene.fast64.sm64.export_type == "C": - export_path, level_name = getPathAndLevel( - props.is_actor_custom_export, - props.actor_custom_path, - props.export_level_name, - props.level_name, - ) + export_path, level_name = props.get_path_and_level(sm64_props) if not props.is_actor_custom_export: applyBasicTweaks(export_path) exportGeolayoutObjectC( + sm64_props, obj, final_transform, export_path, @@ -3037,7 +3055,8 @@ class SM64_ExportGeolayoutArmature(bpy.types.Operator): def execute(self, context): romfileOutput = None tempROM = None - props = context.scene.fast64.sm64.combined_export + sm64_props: SM64_Properties = context.scene.fast64.sm64 + props = sm64_props.combined_export try: armatureObj = None if context.mode != "OBJECT": @@ -3088,17 +3107,13 @@ def execute(self, context): bpy.context.view_layer.objects.active = obj bpy.ops.object.transform_apply(location=False, rotation=True, scale=True, properties=False) if context.scene.fast64.sm64.export_type == "C": - export_path, level_name = getPathAndLevel( - props.is_actor_custom_export, - props.actor_custom_path, - props.export_level_name, - props.level_name, - ) + export_path, level_name = props.get_path_and_level(sm64_props) save_textures = bpy.context.scene.saveTextures if not props.is_actor_custom_export: applyBasicTweaks(export_path) header, fileStatus = exportGeolayoutArmatureC( + sm64_props, armatureObj, obj, final_transform, diff --git a/fast64_internal/sm64/sm64_level_writer.py b/fast64_internal/sm64/sm64_level_writer.py index 969446080..3ac2004d3 100644 --- a/fast64_internal/sm64/sm64_level_writer.py +++ b/fast64_internal/sm64/sm64_level_writer.py @@ -1,7 +1,7 @@ from pathlib import Path import bpy, os, math, re, shutil, mathutils from collections import defaultdict -from typing import NamedTuple +from typing import NamedTuple, TYPE_CHECKING from dataclasses import dataclass, field from bpy.utils import register_class, unregister_class from ..panels import SM64_Panel @@ -34,6 +34,7 @@ applyRotation, raisePluginError, writeMaterialFiles, + as_posix, ) from ..f3d.f3d_gbi import ( @@ -43,6 +44,9 @@ DLFormat, ) +if TYPE_CHECKING: + from .settings.properties import SM64_Properties + levelDefineArgs = { "internal name": 0, @@ -326,7 +330,7 @@ def sub_script_to_c(self, root_persistent_block): result += sub_script.sub_script_to_c(result, root_persistent_block) return result - def to_c(self, areaString): + def to_c(self, areaString, levels_dir: str): if self.marioStart is not None: mario_start_macro = f"\t{self.marioStart.to_c()}," else: @@ -345,10 +349,10 @@ def to_c(self, areaString): '#include "segment_symbols.h"', '#include "level_commands.h"\n', '#include "game/level_update.h"\n', - '#include "levels/scripts.h"\n', + f'#include "{as_posix(Path(levels_dir, "scripts.h"))}"\n', "\n".join(self.actorIncludes), '#include "make_const_nonconst.h"', - f'#include "levels/{self.name}/header.h"\n', + f'#include "{as_posix(Path(levels_dir, self.name, "header.h"))}"\n', # persistent block f"{self.get_persistent_block(PersistentBlocks.scripts)}\n", # sub scripts referenced in previous level script in the same file @@ -530,8 +534,8 @@ def macrosToString(macro_cmds, tabDepth=1, comma=True): return "\n".join([f"{tabs}{macroToString(macro_cmd, comma = comma)}" for macro_cmd in macro_cmds]) -def setStartLevel(basePath, levelEnum): - filepath = os.path.join(basePath, "levels/menu/script.c") +def setStartLevel(basePath, levels_folder: str, levelEnum): + filepath = Path(basePath, levels_folder, "menu", "script.c") data = getDataFromFile(filepath) newData = re.sub("SET\_REG\((((?!\)).)*)\)", "SET_REG(" + levelEnum + ")", data, count=1) @@ -742,7 +746,17 @@ def __init__(self): def export_area_c( - obj, level_data, area_root, prev_level_script, transformMatrix, level_name, level_dir, fModel, DLFormat, savePNG + level_directory: Path, + obj, + level_data, + area_root, + prev_level_script, + transformMatrix, + level_name, + level_dir, + fModel, + DLFormat, + savePNG, ): areaName = f"area_{area_root.areaIndex}" areaDir = os.path.join(level_dir, areaName) @@ -753,7 +767,8 @@ def export_area_c( uses_env_fx = envOption != "ENVFX_MODE_NONE" def include_proto(file_name): - return f'#include "levels/{level_name}/{areaName}/{file_name}"\n' + path = level_directory / areaName / file_name + return f'#include "{as_posix(path)}"\n' # Write geolayout geolayoutGraph, fModel = convertObjectToGeolayout( @@ -820,8 +835,10 @@ def include_proto(file_name): return level_data, fModel, uses_env_fx -def export_level_script_c(obj, prev_level_script, level_name, level_data, level_dir, uses_env_fx): - compressionFmt = bpy.context.scene.fast64.sm64.compression_format +def export_level_script_c( + sm64_props: "SM64_Properties", obj, prev_level_script, level_name, level_data, level_dir, uses_env_fx +): + compressionFmt = sm64_props.compression_format def replace_compressed_segment_load(name: str, segment: int, add_compression_fmt=True): compression_fmts = [compressionFmt.upper()] + list({"MIO0", "YAY0", "RAW"} - {compressionFmt.upper()}) @@ -865,33 +882,47 @@ def replace_compressed_segment_load(name: str, segment: int, add_compression_fmt replaceScriptLoads(prev_level_script, obj) # write data - saveDataToFile(os.path.join(level_dir, "script.c"), prev_level_script.to_c(level_data.area_data)) + saveDataToFile( + os.path.join(level_dir, "script.c"), prev_level_script.to_c(level_data.area_data, sm64_props.levels_folder) + ) return level_data -def exportLevelC(obj, transformMatrix, level_name, exportDir, savePNG, customExport, levelCameraVolumeName, DLFormat): +def exportLevelC( + sm64_props: "SM64_Properties", + obj, + transformMatrix, + level_name, + exportDir, + savePNG, + customExport, + levelCameraVolumeName, + DLFormat, +): fileStatus = SM64OptionalFileStatus() + levels_path = Path(exportDir, sm64_props.levels_folder) if customExport: - level_dir = os.path.join(exportDir, level_name) + level_dir = Path(exportDir, level_name) else: - level_dir = os.path.join(exportDir, "levels/" + level_name) + level_dir = levels_path / level_name + level_directory = Path(sm64_props.levels_folder, level_name) - if not os.path.exists(os.path.join(level_dir, "script.c")): + if not (level_dir / "script.c").exists(): prev_level_script = LevelScript(level_name) else: prev_level_script = parseLevelScript(level_dir, level_name) - if not os.path.exists(level_dir): - os.mkdir(level_dir) + if not level_dir.exists(): + level_dir.mkdir(parents=True) level_data = LevelData(camera_data=f"struct CameraTrigger {levelCameraVolumeName}[] = {{\n") fModel = SM64Model( level_name + "_dl", DLFormat, - bpy.context.scene.fast64.sm64.gfx_write_method, + sm64_props.gfx_write_method, ) childAreas = [child for child in obj.children if child.type == "EMPTY" and child.sm64_obj_type == "Area Root"] if len(childAreas) == 0: @@ -907,7 +938,7 @@ def exportLevelC(obj, transformMatrix, level_name, exportDir, savePNG, customExp prev_level_script.custom_cmds.append( custom_props.get_final_cmd( obj, - bpy.context.scene.fast64.sm64.blender_to_sm64_scale, + sm64_props.blender_to_sm64_scale, child.matrix_world @ yUpToZUp, child.matrix_local, name=obj.name, @@ -937,6 +968,7 @@ def exportLevelC(obj, transformMatrix, level_name, exportDir, savePNG, customExp # write area specific files level_data, fModel, uses_env_fx = export_area_c( + level_directory, obj, level_data, area_root, @@ -952,7 +984,7 @@ def exportLevelC(obj, transformMatrix, level_name, exportDir, savePNG, customExp level_data.camera_data += "\tNULL_TRIGGER\n};" # Generate levelscript string - export_level_script_c(obj, prev_level_script, level_name, level_data, level_dir, uses_env_fx) + export_level_script_c(sm64_props, obj, prev_level_script, level_name, level_data, level_dir, uses_env_fx) if bpy.context.scene.exportHiddenGeometry: restoreHiddenState(hiddenState) @@ -968,7 +1000,8 @@ def exportLevelC(obj, transformMatrix, level_name, exportDir, savePNG, customExp shutil.rmtree(os.path.join(level_dir, folder)) def include_proto(file_name, new_line_first=False): - include = f'#include "levels/{level_name}/{file_name}"' + path = Path(sm64_props.levels_folder, level_name, file_name) + include = f'#include "{as_posix(path)}"' if new_line_first: include = "\n" + include else: @@ -978,13 +1011,15 @@ def include_proto(file_name, new_line_first=False): def write_include(path: Path, include: Path, before_endif=False): return write_or_delete_if_found( path, - [to_include_descriptor(include, Path("levels", level_name, include))], + [to_include_descriptor(include, Path(sm64_props.levels_folder, level_name, include))], path_must_exist=True, footer=END_IF_FOOTER if before_endif else None, ) gfxFormatter = SM64GfxFormatter(ScrollMethod.Vertex) - exportData = fModel.to_c(TextureExportSettings(savePNG, savePNG, f"levels/{level_name}", level_dir), gfxFormatter) + exportData = fModel.to_c( + TextureExportSettings(savePNG, savePNG, as_posix(level_directory), level_dir), gfxFormatter + ) staticData = exportData.staticData dynamicData = exportData.dynamicData texC = exportData.textureData @@ -1023,11 +1058,13 @@ def write_include(path: Path, include: Path, before_endif=False): saveDataToFile(os.path.join(level_dir, "leveldata.inc.c"), level_data.script_data) saveDataToFile(os.path.join(level_dir, "header.inc.h"), level_data.header_data) + levelDefinesPath = levels_path / "level_defines.h" + if customExport: level_data.camera_data = "\n".join( [ "// Replace the level specific camera volume struct in src/game/camera.c with this.", - "// Make sure to also add the struct name to the LEVEL_DEFINE in levels/level_defines.h.", + f"// Make sure to also add the struct name to the LEVEL_DEFINE in {as_posix(levelDefinesPath)}.", level_data.camera_data, ] ) @@ -1048,9 +1085,7 @@ def write_include(path: Path, include: Path, before_endif=False): if DLFormat != DLFormat.Static: # Write material headers write_material_headers( - Path(exportDir), - Path("levels", level_name, "material.inc.c"), - Path("levels", level_name, "material.inc.h"), + Path(exportDir), level_directory / "material.inc.c", level_directory / "material.inc.h" ) # Export camera triggers @@ -1072,8 +1107,7 @@ def write_include(path: Path, include: Path, before_endif=False): if os.path.exists(puppycamAnglesPath) and level_data.puppycam_data != "": overwritePuppycamData(puppycamAnglesPath, levelIDNames[level_name], level_data.puppycam_data) - levelHeadersPath = os.path.join(exportDir, "levels/level_headers.h.in") - levelDefinesPath = os.path.join(exportDir, "levels/level_defines.h") + levelHeadersPath = levels_path / "level_headers.h.in" levelDefines = parseLevelDefines(levelDefinesPath) levelDefineMacro = levelDefines.getOrMakeMacroByLevelName(level_name) levelIndex = levelDefines.defineMacros.index(levelDefineMacro) @@ -1087,7 +1121,7 @@ def write_include(path: Path, include: Path, before_endif=False): levelDefines.write(levelDefinesPath, levelHeadersPath) - courseDefinesPath = os.path.join(exportDir, "levels/course_defines.h") + courseDefinesPath = levels_path / "course_defines.h" courseDefines = parseCourseDefines(courseDefinesPath) courseEnum = levelDefineMacro[1][levelDefineArgs["course name"]] courseMacro = courseDefines.getOrMakeMacroByCourseName(courseEnum, False) @@ -1106,7 +1140,7 @@ def write_include(path: Path, include: Path, before_endif=False): removeActSelectorIgnore(exportDir, levelEnum) if obj.setAsStartLevel: - setStartLevel(exportDir, levelEnum) + setStartLevel(exportDir, sm64_props.levels_folder, levelEnum) geoPath = os.path.join(level_dir, "geo.c") levelDataPath = os.path.join(level_dir, "leveldata.c") @@ -1125,7 +1159,7 @@ def write_include(path: Path, include: Path, before_endif=False): write_include(Path(levelDataPath), Path("leveldata.inc.c")) write_include(Path(headerPath), Path("header.inc.h"), before_endif=True) - old_include = to_include_descriptor(Path("levels", level_name, "texture_include.inc.c")) + old_include = to_include_descriptor(level_directory / "texture_include.inc.c") if fModel.texturesSavedLastExport == 0: textureIncludePath = os.path.join(level_dir, "texture_include.inc.c") if os.path.exists(textureIncludePath): @@ -1142,6 +1176,7 @@ def write_include(path: Path, include: Path, before_endif=False): texscrollGroupInclude = include_proto("header.h") texScrollFileStatus = modifyTexScrollHeadersGroup( + sm64_props, exportDir, texscrollIncludeC, texscrollIncludeH, @@ -1157,52 +1192,6 @@ def write_include(path: Path, include: Path, before_endif=False): return fileStatus -def addGeoC(levelName): - header = ( - "#include \n" - '#include "sm64.h"\n' - '#include "geo_commands.h"\n' - "\n" - '#include "game/level_geo.h"\n' - '#include "game/geo_misc.h"\n' - '#include "game/camera.h"\n' - '#include "game/moving_texture.h"\n' - '#include "game/screen_transition.h"\n' - '#include "game/paintings.h"\n\n' - ) - - header += '#include "levels/' + levelName + '/header.h"\n' - return header - - -def addLevelDataC(levelName): - header = ( - "#include \n" - '#include "sm64.h"\n' - '#include "surface_terrains.h"\n' - '#include "moving_texture_macros.h"\n' - '#include "level_misc_macros.h"\n' - '#include "macro_preset_names.h"\n' - '#include "special_preset_names.h"\n' - '#include "textures.h"\n' - '#include "dialog_ids.h"\n' - "\n" - '#include "make_const_nonconst.h"\n' - ) - - return header - - -def addHeaderC(levelName): - header = ( - "#ifndef " + levelName.upper() + "_HEADER_H\n" + "#define " + levelName.upper() + "_HEADER_H\n" + "\n" - '#include "types.h"\n' - '#include "game/moving_texture.h"\n\n' - ) - - return header - - class SM64_ExportLevel(ObjectDataExporter): # set bl_ properties bl_idname = "object.sm64_export_level" @@ -1212,6 +1201,7 @@ class SM64_ExportLevel(ObjectDataExporter): def execute(self, context): if context.mode != "OBJECT": raise PluginError("Operator can only be used in object mode.") + sm64_props: SM64_Properties = context.scene.fast64.sm64 obj: bpy.types.Object = None try: try: @@ -1233,7 +1223,7 @@ def execute(self, context): raise PluginError("Cannot find level empty.") selectSingleObject(obj) - scaleValue = context.scene.fast64.sm64.blender_to_sm64_scale + scaleValue = sm64_props.blender_to_sm64_scale final_transform = mathutils.Matrix.Diagonal(mathutils.Vector((scaleValue, scaleValue, scaleValue))).to_4x4() except Exception as e: @@ -1244,7 +1234,7 @@ def execute(self, context): applyRotation([obj], math.radians(90), "X") - props = context.scene.fast64.sm64.combined_export + props = sm64_props.combined_export export_path, level_name = props.base_level_path, props.export_level_name if props.is_custom_level: triggerName = "sCam" + level_name.title().replace(" ", "").replace("_", "") @@ -1254,6 +1244,7 @@ def execute(self, context): if not props.non_decomp_level: applyBasicTweaks(export_path) fileStatus = exportLevelC( + sm64_props, obj, final_transform, level_name, diff --git a/fast64_internal/sm64/sm64_objects.py b/fast64_internal/sm64/sm64_objects.py index ecf4a5a88..ec9e4dc7d 100644 --- a/fast64_internal/sm64/sm64_objects.py +++ b/fast64_internal/sm64/sm64_objects.py @@ -1,9 +1,13 @@ -import math, bpy, mathutils -from bpy.utils import register_class, unregister_class -from bpy.types import UILayout +import math +import typing from re import findall, sub from pathlib import Path +import bpy +import mathutils +from bpy.utils import register_class, unregister_class +from bpy.types import UILayout + from bpy.utils import register_class, unregister_class from ..panels import SM64_Panel @@ -28,6 +32,7 @@ raisePluginError, enumExportHeaderType, selectSingleObject, + as_posix, ) from ..f3d.f3d_gbi import ( @@ -81,6 +86,9 @@ from .custom_cmd.properties import SM64_CustomCmdProperties +if typing.TYPE_CHECKING: + from .settings.properties import SM64_Properties + enumTerrain = [ ("Custom", "Custom", "Custom"), ("TERRAIN_GRASS", "Grass", "Grass"), @@ -1621,17 +1629,17 @@ def write_file_lines(self, path, file_lines): # exports the model ID load into the appropriate script.c location def export_script_load(self, context, props): - decomp_path = bpy.context.scene.fast64.sm64.abs_decomp_path + sm64_props: SM64_Properties = context.scene.fast64.sm64 + decomp_path = sm64_props.abs_decomp_path if props.export_header_type == "Level": - # for some reason full_level_path doesn't work here if props.non_decomp_level: - levels_path = Path(props.full_level_path) + levels_path = props.get_full_level_path(sm64_props.levels_folder) else: - levels_path = decomp_path / "levels" / props.export_level_name + levels_path = decomp_path / sm64_props.levels_folder / props.export_level_name script_path = levels_path / "script.c" self.export_level_specific_load(script_path, props) elif props.export_header_type == "Actor": - script_path = decomp_path / "levels" / "scripts.c" + script_path = decomp_path / sm64_props.levels_folder / "scripts.c" self.export_group_script_load(script_path, props) # delims to notify for when to start and end for sig/alt @@ -1826,22 +1834,27 @@ def export_behavior_script(self, context, props): # add at top of bhvs, 3 lines after this is found bhv_data_lines = open(behavior_data, "r").readlines() + sm64_props: SM64_Properties = context.scene.fast64.sm64 + include = None if props.export_header_type == "Actor": - include = f'#include "actors/{toAlnum(props.actor_group_name)}.h"\n' + path = Path(sm64_props.actors_folder) / f"{toAlnum(props.actor_group_name)}.h" + include = f'#include "{as_posix(path)}"\n' elif props.export_header_type == "Level" and not props.non_decomp_level: - include = f'#include "levels/{toAlnum(props.export_level_name)}/header.h"\n' - match_line, sig_insert_line, default_line = self.find_export_lines( - bhv_data_lines, - match_str=include, - alt_condition='#include "', - ) - if match_line: - bhv_data_lines[match_line] = include - elif sig_insert_line: - bhv_data_lines.insert(sig_insert_line + 1, include) - else: - export_line = default_line + 1 if default_line else len(bhv_data_lines) - bhv_data_lines.insert(export_line, include) + path = Path(sm64_props.levels_folder) / f"{toAlnum(props.export_level_name)}" / "header.h" + include = f'#include "{as_posix(path)}"\n' + if include is not None: + match_line, sig_insert_line, default_line = self.find_export_lines( + bhv_data_lines, + match_str=include, + alt_condition='#include "', + ) + if match_line: + bhv_data_lines[match_line] = include + elif sig_insert_line: + bhv_data_lines.insert(sig_insert_line + 1, include) + else: + export_line = default_line + 1 if default_line else len(bhv_data_lines) + bhv_data_lines.insert(export_line, include) export_bhv_name = f"const BehaviorScript {props.bhv_name}[] = {{\n" last_bhv_define = "#define SPAWN_WATER_DROPLET(dropletParams)" @@ -2227,19 +2240,17 @@ def is_actor_custom_export(self): else: return False - @property - def actor_custom_path(self): + def get_actor_custom_path(self, levels_folder: str): if self.export_header_type == "Level": - return self.full_level_path + return self.get_full_level_path(levels_folder) else: return self.custom_export_path - @property - def level_directory(self) -> Path: + def get_level_directory(self, levels_folder: str) -> Path: if self.non_decomp_level: return Path(self.custom_level_name) level_name = self.custom_level_name if self.level_name == "Custom" else self.level_name - return Path("levels") / level_name + return Path(levels_folder) / level_name @property def base_level_path(self): @@ -2247,9 +2258,20 @@ def base_level_path(self): return Path(bpy.path.abspath(self.custom_level_path)) return bpy.context.scene.fast64.sm64.abs_decomp_path - @property - def full_level_path(self): - return self.base_level_path / self.level_directory + def get_full_level_path(self, levels_folder: str): + return self.base_level_path / self.get_level_directory(levels_folder) + + def get_path_and_level(self, sm64_props: "SM64_Properties"): + if self.is_actor_custom_export: + export_path = bpy.path.abspath(str(self.get_actor_custom_path(sm64_props.levels_folder))) + level_name = self.export_level_name + else: + export_path = str(sm64_props.abs_decomp_path) + if self.level_name == "Custom": + level_name = self.export_level_name + else: + level_name = self.level_name + return export_path, level_name # remove user prefixes/naming that I will be adding, such as _col, _geo etc. def filter_name(self, name, force_filtering=False): @@ -2331,27 +2353,33 @@ def export_locations(self) -> str | None: return None def draw_level_path(self, layout): + sm64_props: SM64_Properties = bpy.context.scene.fast64.sm64 if not directory_ui_warnings(layout, self.base_level_path): return if self.non_decomp_level: - layout.label(text=f"Level export path: {self.full_level_path}") + layout.label(text=f"Level export path: {self.get_full_level_path(sm64_props.levels_folder)}") else: - layout.label(text=f"Level export directory: {self.level_directory}") + layout.label(text=f"Level export directory: {self.get_level_directory(sm64_props.levels_folder)}") return True def draw_actor_path(self, layout): if self.export_locations is None: return False - decomp_path = bpy.context.scene.fast64.sm64.abs_decomp_path + sm64_props: SM64_Properties = bpy.context.scene.fast64.sm64 + decomp_path = sm64_props.abs_decomp_path if self.export_header_type == "Actor": - actor_path = decomp_path / "actors" + actor_path = decomp_path / sm64_props.actors_folder if not filepath_ui_warnings(layout, (actor_path / self.actor_group_name).with_suffix(".c")): return False - layout.label(text=f"Actor export path: actors/{self.export_locations}/") + exports_locations = Path(sm64_props.actors_folder) / self.export_locations + layout.label(text=f"Actor export directory: {as_posix(exports_locations)}") elif self.export_header_type == "Level": - if not directory_ui_warnings(layout, self.full_level_path): + full_level_path = self.get_full_level_path(sm64_props.levels_folder) + if not directory_ui_warnings(layout, full_level_path): return False - level_path = self.full_level_path if self.non_decomp_level else self.level_directory + level_path = ( + full_level_path if self.non_decomp_level else self.get_level_directory(sm64_props.levels_folder) + ) layout.label(text=f"Actor export path: {level_path / self.export_locations}/") elif self.export_header_type == "Custom": custom_path = Path(bpy.path.abspath(self.custom_export_path)) diff --git a/fast64_internal/sm64/sm64_texscroll.py b/fast64_internal/sm64/sm64_texscroll.py index c39de7fd0..7fe7b6095 100644 --- a/fast64_internal/sm64/sm64_texscroll.py +++ b/fast64_internal/sm64/sm64_texscroll.py @@ -1,9 +1,16 @@ from pathlib import Path -import os, re, bpy -from ..utility import PluginError, getDataFromFile, saveDataToFile, CScrollData, CData +import os +import re +import bpy +import typing + +from ..utility import PluginError, getDataFromFile, saveDataToFile, CScrollData, CData, filepath_checks from .c_templates.tile_scroll import tile_scroll_c, tile_scroll_h from .sm64_utility import END_IF_FOOTER, ModifyFoundDescriptor, getMemoryCFilePath, write_or_delete_if_found +if typing.TYPE_CHECKING: + from .settings.properties import SM64_Properties + # This is for writing framework for scroll code. # Actual scroll code found in f3d_gbi.py (FVertexScrollData) @@ -13,13 +20,13 @@ def __init__(self): self.starSelectC = False -def readSegmentInfo(baseDir): +def readSegmentInfo(sm64_props: "SM64_Properties", baseDir): ldPath = os.path.join(baseDir, "sm64.ld") ldFile = open(ldPath, "r", newline="\n") ldData = ldFile.read() ldFile.close() - compressionFmt = bpy.context.scene.fast64.sm64.compression_format + compressionFmt = sm64_props.compression_format segDict = {} for matchResult in re.finditer( "(?