From 5445d2ebe103bf944da6de72d9a9faa86a1c19f9 Mon Sep 17 00:00:00 2001 From: Yanis <35189056+Yanis002@users.noreply.github.com> Date: Tue, 20 May 2025 20:30:59 +0200 Subject: [PATCH] [OoT] Move collection operators/functions from oot_utility.py (#486) move collection stuff to its own file --- fast64_internal/oot/__init__.py | 7 +- fast64_internal/oot/actor/properties.py | 3 +- fast64_internal/oot/collection_utility.py | 177 +++++++++++++++++++++ fast64_internal/oot/cutscene/operators.py | 2 +- fast64_internal/oot/cutscene/properties.py | 3 +- fast64_internal/oot/oot_utility.py | 174 -------------------- fast64_internal/oot/room/properties.py | 3 +- fast64_internal/oot/scene/properties.py | 10 +- 8 files changed, 189 insertions(+), 190 deletions(-) create mode 100644 fast64_internal/oot/collection_utility.py diff --git a/fast64_internal/oot/__init__.py b/fast64_internal/oot/__init__.py index c41fa07..d059133 100644 --- a/fast64_internal/oot/__init__.py +++ b/fast64_internal/oot/__init__.py @@ -7,7 +7,8 @@ from .scene.panels import scene_panels_register, scene_panels_unregister from .props_panel_main import oot_obj_panel_register, oot_obj_panel_unregister, oot_obj_register, oot_obj_unregister from .skeleton.properties import OOTSkeletonImportSettings, OOTSkeletonExportSettings -from .oot_utility import oot_utility_register, oot_utility_unregister, setAllActorsVisibility +from .collection_utility import collections_register, collections_unregister +from .oot_utility import setAllActorsVisibility from .file_settings import file_register, file_unregister from .collision.properties import OOTCollisionExportSettings @@ -147,7 +148,7 @@ def oot_panel_unregister(): def oot_register(registerPanels): oot_operator_register() - oot_utility_register() + collections_register() collision_ops_register() # register first, so panel goes above mat panel collision_props_register() cutscene_props_register() @@ -186,7 +187,7 @@ def oot_unregister(unregisterPanels): unregister_class(cls) oot_operator_unregister() - oot_utility_unregister() + collections_unregister() collision_ops_unregister() # register first, so panel goes above mat panel collision_props_unregister() oot_obj_unregister() diff --git a/fast64_internal/oot/actor/properties.py b/fast64_internal/oot/actor/properties.py index ef3431c..17b1fcb 100644 --- a/fast64_internal/oot/actor/properties.py +++ b/fast64_internal/oot/actor/properties.py @@ -8,6 +8,7 @@ from ..oot_constants import ootData, ootEnumCamTransition from ..oot_upgrade import upgradeActors from ..scene.properties import OOTAlternateSceneHeaderProperty from ..room.properties import OOTAlternateRoomHeaderProperty +from ..collection_utility import drawAddButton, drawCollectionOps from .operators import ( OOT_SearchActorIDEnumOperator, OOT_SearchChestContentEnumOperator, @@ -17,8 +18,6 @@ from .operators import ( from ..oot_utility import ( getRoomObj, getEnumName, - drawAddButton, - drawCollectionOps, drawEnumWithCustom, getEvalParams, getEvalParamsInt, diff --git a/fast64_internal/oot/collection_utility.py b/fast64_internal/oot/collection_utility.py new file mode 100644 index 0000000..98da2cc --- /dev/null +++ b/fast64_internal/oot/collection_utility.py @@ -0,0 +1,177 @@ +import bpy + +from bpy.types import Operator +from bpy.utils import register_class, unregister_class +from bpy.props import IntProperty, StringProperty +from ..utility import PluginError, ootGetSceneOrRoomHeader + + +class OOTCollectionAdd(Operator): + bl_idname = "object.oot_collection_add" + bl_label = "Add Item" + bl_options = {"REGISTER", "UNDO"} + + option: IntProperty() + collectionType: StringProperty(default="Actor") + subIndex: IntProperty(default=0) + objName: StringProperty() + + def execute(self, context): + collection = getCollection(self.objName, self.collectionType, self.subIndex) + + collection.add() + collection.move(len(collection) - 1, self.option) + return {"FINISHED"} + + +class OOTCollectionRemove(Operator): + bl_idname = "object.oot_collection_remove" + bl_label = "Remove Item" + bl_options = {"REGISTER", "UNDO"} + + option: IntProperty() + collectionType: StringProperty(default="Actor") + subIndex: IntProperty(default=0) + objName: StringProperty() + + def execute(self, context): + collection = getCollection(self.objName, self.collectionType, self.subIndex) + collection.remove(self.option) + return {"FINISHED"} + + +class OOTCollectionMove(Operator): + bl_idname = "object.oot_collection_move" + bl_label = "Move Item" + bl_options = {"REGISTER", "UNDO"} + + option: IntProperty() + offset: IntProperty() + subIndex: IntProperty(default=0) + objName: StringProperty() + + collectionType: StringProperty(default="Actor") + + def execute(self, context): + collection = getCollection(self.objName, self.collectionType, self.subIndex) + collection.move(self.option, self.option + self.offset) + return {"FINISHED"} + + +def getCollectionFromIndex(obj, prop, subIndex, isRoom): + header = ootGetSceneOrRoomHeader(obj, subIndex, isRoom) + return getattr(header, prop) + + +# Operators cannot store mutable references (?), so to reuse PropertyCollection modification code we do this. +# Save a string identifier in the operator, then choose the member variable based on that. +# subIndex is for a collection within a collection element +def getCollection(objName, collectionType, subIndex): + obj = bpy.data.objects[objName] + if collectionType == "Actor": + collection = obj.ootActorProperty.headerSettings.cutsceneHeaders + elif collectionType == "Transition Actor": + collection = obj.ootTransitionActorProperty.actor.headerSettings.cutsceneHeaders + elif collectionType == "Entrance": + collection = obj.ootEntranceProperty.actor.headerSettings.cutsceneHeaders + elif collectionType == "Room": + collection = obj.ootAlternateRoomHeaders.cutsceneHeaders + elif collectionType == "Scene": + collection = obj.ootAlternateSceneHeaders.cutsceneHeaders + elif collectionType == "Light": + collection = getCollectionFromIndex(obj, "lightList", subIndex, False) + elif collectionType == "Exit": + collection = getCollectionFromIndex(obj, "exitList", subIndex, False) + elif collectionType == "Object": + collection = getCollectionFromIndex(obj, "objectList", subIndex, True) + elif collectionType == "Curve": + collection = obj.ootSplineProperty.headerSettings.cutsceneHeaders + elif collectionType.startswith("CSHdr."): + # CSHdr.HeaderNumber[.ListType] + # Specifying ListType means uses subIndex + toks = collectionType.split(".") + assert len(toks) in [2, 3] + hdrnum = int(toks[1]) + collection = getCollectionFromIndex(obj, "csLists", hdrnum, False) + if len(toks) == 3: + collection = getattr(collection[subIndex], toks[2]) + elif collectionType.startswith("Cutscene."): + # Cutscene.ListType + toks = collectionType.split(".") + assert len(toks) == 2 + collection = obj.ootCutsceneProperty.csLists + collection = getattr(collection[subIndex], toks[1]) + elif collectionType == "Cutscene": + collection = obj.ootCutsceneProperty.csLists + elif collectionType == "extraCutscenes": + collection = obj.ootSceneHeader.extraCutscenes + elif collectionType == "BgImage": + collection = obj.ootRoomHeader.bgImageList + else: + raise PluginError("Invalid collection type: " + collectionType) + + return collection + + +def drawAddButton(layout, index, collectionType, subIndex, objName): + if subIndex is None: + subIndex = 0 + addOp = layout.operator(OOTCollectionAdd.bl_idname) + addOp.option = index + addOp.collectionType = collectionType + addOp.subIndex = subIndex + addOp.objName = objName + + +def drawCollectionOps(layout, index, collectionType, subIndex, objName, allowAdd=True, compact=False): + if subIndex is None: + subIndex = 0 + + if not compact: + buttons = layout.row(align=True) + else: + buttons = layout + + if allowAdd: + addOp = buttons.operator(OOTCollectionAdd.bl_idname, text="Add" if not compact else "", icon="ADD") + addOp.option = index + 1 + addOp.collectionType = collectionType + addOp.subIndex = subIndex + addOp.objName = objName + + removeOp = buttons.operator(OOTCollectionRemove.bl_idname, text="Delete" if not compact else "", icon="REMOVE") + removeOp.option = index + removeOp.collectionType = collectionType + removeOp.subIndex = subIndex + removeOp.objName = objName + + moveUp = buttons.operator(OOTCollectionMove.bl_idname, text="Up" if not compact else "", icon="TRIA_UP") + moveUp.option = index + moveUp.offset = -1 + moveUp.collectionType = collectionType + moveUp.subIndex = subIndex + moveUp.objName = objName + + moveDown = buttons.operator(OOTCollectionMove.bl_idname, text="Down" if not compact else "", icon="TRIA_DOWN") + moveDown.option = index + moveDown.offset = 1 + moveDown.collectionType = collectionType + moveDown.subIndex = subIndex + moveDown.objName = objName + + +collections_classes = ( + OOTCollectionAdd, + OOTCollectionRemove, + OOTCollectionMove, +) + + +def collections_register(): + for cls in collections_classes: + register_class(cls) + + +def collections_unregister(): + for cls in reversed(collections_classes): + unregister_class(cls) diff --git a/fast64_internal/oot/cutscene/operators.py b/fast64_internal/oot/cutscene/operators.py index 408811b..c3898b3 100644 --- a/fast64_internal/oot/cutscene/operators.py +++ b/fast64_internal/oot/cutscene/operators.py @@ -8,7 +8,7 @@ from bpy.props import StringProperty, EnumProperty, IntProperty from bpy.types import Scene, Operator, Context from bpy.utils import register_class, unregister_class from ...utility import CData, PluginError, writeCData, raisePluginError -from ..oot_utility import getCollection +from ..collection_utility import getCollection from ..oot_constants import ootData from .constants import ootEnumCSTextboxType, ootEnumCSListType from .importer import importCutsceneData diff --git a/fast64_internal/oot/cutscene/properties.py b/fast64_internal/oot/cutscene/properties.py index f2f6c3c..4e95ac7 100644 --- a/fast64_internal/oot/cutscene/properties.py +++ b/fast64_internal/oot/cutscene/properties.py @@ -2,7 +2,8 @@ from bpy.types import PropertyGroup, Object, UILayout, Scene, Context from bpy.props import StringProperty, EnumProperty, IntProperty, BoolProperty, CollectionProperty, PointerProperty from bpy.utils import register_class, unregister_class from ...utility import PluginError, prop_split -from ..oot_utility import OOTCollectionAdd, drawCollectionOps, getEnumName +from ..collection_utility import OOTCollectionAdd, drawCollectionOps +from ..oot_utility import getEnumName from ..oot_constants import ootData from ..oot_upgrade import upgradeCutsceneSubProps, upgradeCSListProps, upgradeCutsceneProperty from .operators import OOTCSTextAdd, OOT_SearchCSDestinationEnumOperator, OOTCSListAdd, OOT_SearchCSSeqOperator diff --git a/fast64_internal/oot/oot_utility.py b/fast64_internal/oot/oot_utility.py index 51793fc..1f8bc4a 100644 --- a/fast64_internal/oot/oot_utility.py +++ b/fast64_internal/oot/oot_utility.py @@ -6,8 +6,6 @@ import re from ast import parse, Expression, Constant, UnaryOp, USub, Invert, BinOp from mathutils import Vector from bpy.types import Object -from bpy.utils import register_class, unregister_class -from bpy.types import Object from typing import Callable, Optional, TYPE_CHECKING, List from .oot_constants import ootSceneIDToName from dataclasses import dataclass @@ -21,7 +19,6 @@ from ..utility import ( setOrigin, applyRotation, cleanupDuplicatedObjects, - ootGetSceneOrRoomHeader, hexOrDecInt, binOps, ) @@ -646,160 +643,6 @@ def getCutsceneName(obj): return name -def getCollectionFromIndex(obj, prop, subIndex, isRoom): - header = ootGetSceneOrRoomHeader(obj, subIndex, isRoom) - return getattr(header, prop) - - -# Operators cannot store mutable references (?), so to reuse PropertyCollection modification code we do this. -# Save a string identifier in the operator, then choose the member variable based on that. -# subIndex is for a collection within a collection element -def getCollection(objName, collectionType, subIndex): - obj = bpy.data.objects[objName] - if collectionType == "Actor": - collection = obj.ootActorProperty.headerSettings.cutsceneHeaders - elif collectionType == "Transition Actor": - collection = obj.ootTransitionActorProperty.actor.headerSettings.cutsceneHeaders - elif collectionType == "Entrance": - collection = obj.ootEntranceProperty.actor.headerSettings.cutsceneHeaders - elif collectionType == "Room": - collection = obj.ootAlternateRoomHeaders.cutsceneHeaders - elif collectionType == "Scene": - collection = obj.ootAlternateSceneHeaders.cutsceneHeaders - elif collectionType == "Light": - collection = getCollectionFromIndex(obj, "lightList", subIndex, False) - elif collectionType == "Exit": - collection = getCollectionFromIndex(obj, "exitList", subIndex, False) - elif collectionType == "Object": - collection = getCollectionFromIndex(obj, "objectList", subIndex, True) - elif collectionType == "Curve": - collection = obj.ootSplineProperty.headerSettings.cutsceneHeaders - elif collectionType.startswith("CSHdr."): - # CSHdr.HeaderNumber[.ListType] - # Specifying ListType means uses subIndex - toks = collectionType.split(".") - assert len(toks) in [2, 3] - hdrnum = int(toks[1]) - collection = getCollectionFromIndex(obj, "csLists", hdrnum, False) - if len(toks) == 3: - collection = getattr(collection[subIndex], toks[2]) - elif collectionType.startswith("Cutscene."): - # Cutscene.ListType - toks = collectionType.split(".") - assert len(toks) == 2 - collection = obj.ootCutsceneProperty.csLists - collection = getattr(collection[subIndex], toks[1]) - elif collectionType == "Cutscene": - collection = obj.ootCutsceneProperty.csLists - elif collectionType == "extraCutscenes": - collection = obj.ootSceneHeader.extraCutscenes - elif collectionType == "BgImage": - collection = obj.ootRoomHeader.bgImageList - else: - raise PluginError("Invalid collection type: " + collectionType) - - return collection - - -def drawAddButton(layout, index, collectionType, subIndex, objName): - if subIndex is None: - subIndex = 0 - addOp = layout.operator(OOTCollectionAdd.bl_idname) - addOp.option = index - addOp.collectionType = collectionType - addOp.subIndex = subIndex - addOp.objName = objName - - -def drawCollectionOps(layout, index, collectionType, subIndex, objName, allowAdd=True, compact=False): - if subIndex is None: - subIndex = 0 - - if not compact: - buttons = layout.row(align=True) - else: - buttons = layout - - if allowAdd: - addOp = buttons.operator(OOTCollectionAdd.bl_idname, text="Add" if not compact else "", icon="ADD") - addOp.option = index + 1 - addOp.collectionType = collectionType - addOp.subIndex = subIndex - addOp.objName = objName - - removeOp = buttons.operator(OOTCollectionRemove.bl_idname, text="Delete" if not compact else "", icon="REMOVE") - removeOp.option = index - removeOp.collectionType = collectionType - removeOp.subIndex = subIndex - removeOp.objName = objName - - moveUp = buttons.operator(OOTCollectionMove.bl_idname, text="Up" if not compact else "", icon="TRIA_UP") - moveUp.option = index - moveUp.offset = -1 - moveUp.collectionType = collectionType - moveUp.subIndex = subIndex - moveUp.objName = objName - - moveDown = buttons.operator(OOTCollectionMove.bl_idname, text="Down" if not compact else "", icon="TRIA_DOWN") - moveDown.option = index - moveDown.offset = 1 - moveDown.collectionType = collectionType - moveDown.subIndex = subIndex - moveDown.objName = objName - - -class OOTCollectionAdd(bpy.types.Operator): - bl_idname = "object.oot_collection_add" - bl_label = "Add Item" - bl_options = {"REGISTER", "UNDO"} - - option: bpy.props.IntProperty() - collectionType: bpy.props.StringProperty(default="Actor") - subIndex: bpy.props.IntProperty(default=0) - objName: bpy.props.StringProperty() - - def execute(self, context): - collection = getCollection(self.objName, self.collectionType, self.subIndex) - - collection.add() - collection.move(len(collection) - 1, self.option) - return {"FINISHED"} - - -class OOTCollectionRemove(bpy.types.Operator): - bl_idname = "object.oot_collection_remove" - bl_label = "Remove Item" - bl_options = {"REGISTER", "UNDO"} - - option: bpy.props.IntProperty() - collectionType: bpy.props.StringProperty(default="Actor") - subIndex: bpy.props.IntProperty(default=0) - objName: bpy.props.StringProperty() - - def execute(self, context): - collection = getCollection(self.objName, self.collectionType, self.subIndex) - collection.remove(self.option) - return {"FINISHED"} - - -class OOTCollectionMove(bpy.types.Operator): - bl_idname = "object.oot_collection_move" - bl_label = "Move Item" - bl_options = {"REGISTER", "UNDO"} - - option: bpy.props.IntProperty() - offset: bpy.props.IntProperty() - subIndex: bpy.props.IntProperty(default=0) - objName: bpy.props.StringProperty() - - collectionType: bpy.props.StringProperty(default="Actor") - - def execute(self, context): - collection = getCollection(self.objName, self.collectionType, self.subIndex) - collection.move(self.option, self.option + self.offset) - return {"FINISHED"} - - def getHeaderSettings(actorObj: bpy.types.Object): itemType = actorObj.ootEmptyType if actorObj.type == "EMPTY": @@ -819,23 +662,6 @@ def getHeaderSettings(actorObj: bpy.types.Object): return headerSettings -oot_utility_classes = ( - OOTCollectionAdd, - OOTCollectionRemove, - OOTCollectionMove, -) - - -def oot_utility_register(): - for cls in oot_utility_classes: - register_class(cls) - - -def oot_utility_unregister(): - for cls in reversed(oot_utility_classes): - unregister_class(cls) - - def getActiveHeaderIndex() -> int: # All scenes/rooms should have synchronized tabs from property callbacks headerObjs = [obj for obj in bpy.data.objects if obj.ootEmptyType == "Scene" or obj.ootEmptyType == "Room"] diff --git a/fast64_internal/oot/room/properties.py b/fast64_internal/oot/room/properties.py index 1e9d643..733b2b3 100644 --- a/fast64_internal/oot/room/properties.py +++ b/fast64_internal/oot/room/properties.py @@ -2,7 +2,8 @@ import bpy from bpy.types import PropertyGroup, UILayout, Image, Object from bpy.utils import register_class, unregister_class from ...utility import prop_split -from ..oot_utility import drawCollectionOps, onMenuTabChange, onHeaderMenuTabChange, drawEnumWithCustom, drawAddButton +from ..collection_utility import drawCollectionOps, drawAddButton +from ..oot_utility import onMenuTabChange, onHeaderMenuTabChange, drawEnumWithCustom from ..oot_upgrade import upgradeRoomHeaders from .operators import OOT_SearchObjectEnumOperator diff --git a/fast64_internal/oot/scene/properties.py b/fast64_internal/oot/scene/properties.py index b48948e..1f2414d 100644 --- a/fast64_internal/oot/scene/properties.py +++ b/fast64_internal/oot/scene/properties.py @@ -13,14 +13,8 @@ from bpy.utils import register_class, unregister_class from ...render_settings import on_update_oot_render_settings from ...utility import prop_split, customExportWarning from ..cutscene.constants import ootEnumCSWriteType - -from ..oot_utility import ( - onMenuTabChange, - onHeaderMenuTabChange, - drawCollectionOps, - drawEnumWithCustom, - drawAddButton, -) +from ..collection_utility import drawCollectionOps, drawAddButton +from ..oot_utility import onMenuTabChange, onHeaderMenuTabChange, drawEnumWithCustom from ..oot_constants import ( ootEnumMusicSeq,