Merge pull request #269 from Dragorn421/quick_import

[OoT] Add Quick Import button
This commit is contained in:
Sauraen
2023-12-28 21:12:45 -08:00
committed by GitHub
3 changed files with 156 additions and 0 deletions
+38
View File
@@ -8,6 +8,7 @@ from ...operators import AddWaterBox, addMaterialByName
from ...utility import parentObject, setOrigin
from ..cutscene.motion.utility import setupCutscene, createNewCameraShot
from ..oot_utility import getNewPath
from .quick_import import QuickImportAborted, quick_import_exec
class OOT_AddWaterBox(AddWaterBox):
@@ -255,3 +256,40 @@ class OOTClearTransformAndLock(Operator):
return {"FINISHED"}
except:
return {"CANCELLED"}
class OOTQuickImport(Operator):
bl_idname = "object.oot_quick_import"
bl_label = "Quick Import"
bl_options = {"REGISTER", "UNDO"}
bl_description = (
"Import (almost) anything by inputting a symbol name from an object."
" This operator automatically finds the file to import from (within objects)"
)
sym_name: StringProperty(
name="Symbol name",
description=(
"Which symbol to import."
" This may be a display list (e.g. gBoomerangDL), "
"a skeleton (e.g. object_daiku_Skel_007958), "
"an animation (with the appropriate skeleton selected, e.g. object_daiku_Anim_008164)"
),
)
def invoke(self, context, event):
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
self.layout.prop(self, "sym_name", text="Symbol")
def execute(self, context: Context):
try:
quick_import_exec(
context,
self.sym_name,
)
except QuickImportAborted as e:
self.report({"ERROR"}, e.message)
return {"CANCELLED"}
return {"FINISHED"}
+3
View File
@@ -8,6 +8,7 @@ from .operators import (
OOT_AddCutscene,
OOT_AddPath,
OOTClearTransformAndLock,
OOTQuickImport,
)
@@ -24,6 +25,7 @@ class OoT_ToolsPanel(OOT_Panel):
col.operator(OOT_AddCutscene.bl_idname)
col.operator(OOT_AddPath.bl_idname)
col.operator(OOTClearTransformAndLock.bl_idname)
col.operator(OOTQuickImport.bl_idname)
oot_operator_panel_classes = [
@@ -38,6 +40,7 @@ toolOpsToRegister = [
OOT_AddCutscene,
OOT_AddPath,
OOTClearTransformAndLock,
OOTQuickImport,
]
+115
View File
@@ -0,0 +1,115 @@
from pathlib import Path
import os
import re
import bpy
from ..f3d.properties import OOTDLImportSettings
from ..skeleton.properties import OOTSkeletonImportSettings
from ..animation.properties import OOTAnimImportSettingsProperty
class QuickImportAborted(Exception):
def __init__(self, message):
super().__init__(message)
self.message = message
def quick_import_exec(context: bpy.types.Context, sym_name: str):
sym_name = sym_name.strip()
if sym_name == "":
raise QuickImportAborted("No symbol name given")
if not all(
(
"a" <= c <= "z"
or "A" <= c <= "Z"
or "0" <= c <= "9"
or c
in {
"_",
}
)
for c in sym_name
):
raise QuickImportAborted("Symbol names only have characters a-zA-Z0-9_")
sym_def_pattern = re.compile(rf"([^\s]+)\s+{sym_name}\s*(\[[^\]]*\])?\s*=")
base_dir_p = Path(context.scene.ootDecompPath)
assets_objects_dir_p = base_dir_p / "assets" / "objects"
all_found_defs: dict[Path, list[tuple[str, str]]] = dict()
for dirpath, dirnames, filenames in os.walk(assets_objects_dir_p):
dirpath_p = Path(dirpath)
for filename in filenames:
file_p = dirpath_p / filename
# Only look into C files
if file_p.suffix != ".c":
continue
source = file_p.read_text()
# Simple check to see if we should look into this file any further
if sym_name not in source:
continue
found_defs = sym_def_pattern.findall(source)
print(file_p, f"{found_defs=}")
all_found_defs[file_p] = found_defs
# Ideally if for example sym_name was gLinkAdultHookshotTipDL,
# all_found_defs now contains:
# {Path('.../assets/objects/object_link_boy/object_link_boy.c'): [('Gfx', '[]')]}
# or with gButterflySkel:
# {Path('.../assets/objects/gameplay_field_keep/gameplay_field_keep.c'): [('SkeletonHeader', '')]}
if len(all_found_defs) == 0:
raise QuickImportAborted(f"Couldn't find a definition of {sym_name}")
if len(all_found_defs) > 1:
raise QuickImportAborted(
f"Found definitions of {sym_name} in several files: "
+ ", ".join(str(p.relative_to(assets_objects_dir_p)) for p in all_found_defs.keys())
)
assert len(all_found_defs) == 1
sym_file_p, sym_defs = list(all_found_defs.items())[0]
if len(sym_defs) > 1:
raise QuickImportAborted(
f"Found several definitions of {sym_name} in {sym_file_p.relative_to(assets_objects_dir_p)}"
)
# We found a single definition of the symbol
sym_def_type, sym_def_array_decl = sym_defs[0]
is_array = sym_def_array_decl != ""
object_name = sym_file_p.relative_to(assets_objects_dir_p).parts[0]
if sym_def_type == "Gfx" and is_array:
settings: OOTDLImportSettings = context.scene.fast64.oot.DLImportSettings
settings.name = sym_name
settings.folder = object_name
settings.actorOverlayName = ""
settings.isCustom = False
bpy.ops.object.oot_import_dl()
elif sym_def_type in {"SkeletonHeader", "FlexSkeletonHeader"} and not is_array:
settings: OOTSkeletonImportSettings = context.scene.fast64.oot.skeletonImportSettings
settings.isCustom = False
if sym_name == "gLinkAdultSkel":
settings.mode = "Adult Link"
elif sym_name == "gLinkChildSkel":
settings.mode = "Child Link"
else:
settings.mode = "Generic"
settings.name = sym_name
settings.folder = object_name
settings.actorOverlayName = ""
bpy.ops.object.oot_import_skeleton()
elif sym_def_type == "AnimationHeader" and not is_array:
settings: OOTAnimImportSettingsProperty = context.scene.fast64.oot.animImportSettings
settings.isCustom = False
settings.isLink = False
settings.animName = sym_name
settings.folderName = object_name
bpy.ops.object.oot_import_anim()
else:
raise QuickImportAborted(
f"Don't know how to import {sym_def_type}"
+ ("[]" if is_array else "")
+ f" (symbol found in {object_name})"
)