Skip to content

Commit

Permalink
cs import additions/fixes (single import, quick import)
Browse files Browse the repository at this point in the history
  • Loading branch information
Yanis002 committed Jan 16, 2024
1 parent 37aacff commit 960a83f
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 37 deletions.
7 changes: 5 additions & 2 deletions fast64_internal/oot/cutscene/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def __post_init__(self):
class CutsceneCmdActorCue(CutsceneCmdBase):
"""This class contains a single Actor Cue command data"""

actionID: Optional[int] = None
actionID: Optional[int | str] = None
rot: list[str] = field(default_factory=list)
startPos: list[int] = field(default_factory=list)
endPos: list[int] = field(default_factory=list)
Expand All @@ -65,7 +65,10 @@ def __post_init__(self):
if self.params is not None:
self.startFrame = getInteger(self.params[1])
self.endFrame = getInteger(self.params[2])
self.actionID = getInteger(self.params[0])
try:
self.actionID = getInteger(self.params[0])
except ValueError:
self.actionID = self.params[0]
self.rot = [getRotation(self.params[3]), getRotation(self.params[4]), getRotation(self.params[5])]
self.startPos = [getInteger(self.params[6]), getInteger(self.params[7]), getInteger(self.params[8])]
self.endPos = [getInteger(self.params[9]), getInteger(self.params[10]), getInteger(self.params[11])]
Expand Down
21 changes: 17 additions & 4 deletions fast64_internal/oot/cutscene/importer/classes.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import bpy

from dataclasses import dataclass
from typing import TYPE_CHECKING
from typing import Optional, TYPE_CHECKING
from bpy.types import Object, Armature
from ....utility import PluginError
from ..motion.utility import setupCutscene, getBlenderPosition, getInteger
Expand Down Expand Up @@ -46,8 +46,9 @@ class PropertyData:
class CutsceneImport(CutsceneObjectFactory):
"""This class contains functions to create the new cutscene Blender data"""

filePath: str # used when importing from the panel
fileData: str # used when importing the cutscenes when importing a scene
filePath: Optional[str] # used when importing from the panel
fileData: Optional[str] # used when importing the cutscenes when importing a scene
csName: Optional[str] # used when import a specific cutscene

def getCmdParams(self, data: str, cmdName: str, paramNumber: int):
"""Returns the list of every parameter of the given command"""
Expand Down Expand Up @@ -86,6 +87,13 @@ def getParsedCutscenes(self):
for oldName in oldNames:
fileData = fileData.replace(f"{oldName}(", f"{ootCSLegacyToNewCmdNames[oldName]}(")

# make a list of existing cutscene names, to skip importing them if found
existingCutsceneNames = [
csObj.name.removeprefix("Cutscene.")
for csObj in bpy.data.objects
if csObj.type == "EMPTY" and csObj.ootEmptyType == "Cutscene"
]

# parse cutscenes
fileLines = fileData.split("\n")
csData = []
Expand All @@ -94,6 +102,10 @@ def getParsedCutscenes(self):
for line in fileLines:
if not line.startswith("//") and not line.startswith("/*"):
if "CutsceneData " in line:
# split with "[" just in case the array has a set size
csName = line.split(" ")[1].split("[")[0]
if csName in existingCutsceneNames:
continue
foundCutscene = True

if foundCutscene:
Expand All @@ -102,7 +114,8 @@ def getParsedCutscenes(self):
line += fileLines[fileLines.index(line) + 1].strip()

if len(csData) == 0 or "CS_" in line:
csData.append(line)
if self.csName is None or self.csName == csName:
csData.append(line)

if "};" in line:
foundCutscene = False
Expand Down
5 changes: 3 additions & 2 deletions fast64_internal/oot/cutscene/importer/functions.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import bpy

from typing import Optional
from .classes import CutsceneImport


def importCutsceneData(filePath: str, sceneData: str):
def importCutsceneData(filePath: Optional[str], sceneData: Optional[str], csName: Optional[str] = None):
"""Initialises and imports the cutscene data from either a file or the scene data"""
# NOTE: ``sceneData`` is the data read when importing a scene
csMotionImport = CutsceneImport(filePath, sceneData)
csMotionImport = CutsceneImport(filePath, sceneData, csName)
return csMotionImport.setCutsceneData(bpy.context.scene.ootCSNumber)
11 changes: 8 additions & 3 deletions fast64_internal/oot/cutscene/operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,17 @@ def execute(self, context):

class OOT_ImportCutscene(Operator):
bl_idname = "object.oot_import_cutscenes"
bl_label = "Import All Cutscenes"
bl_options = {"REGISTER", "UNDO", "PRESET"}
bl_label = "Import Cutscenes"
bl_options = {"REGISTER", "UNDO"}

def execute(self, context):
try:
if context.mode != "OBJECT":
object.mode_set(mode="OBJECT")

path = abspath(context.scene.ootCutsceneImportPath)
context.scene.ootCSNumber = importCutsceneData(path, None)
csName = context.scene.ootCSImportName if len(context.scene.ootCSImportName) > 0 else None
context.scene.ootCSNumber = importCutsceneData(path, None, csName)

self.report({"INFO"}, "Successfully imported cutscenes")
return {"FINISHED"}
Expand Down Expand Up @@ -295,12 +296,16 @@ def cutscene_ops_register():
Scene.ootCutsceneExportPath = StringProperty(name="File", subtype="FILE_PATH")
Scene.ootCutsceneImportPath = StringProperty(name="File", subtype="FILE_PATH")
Scene.ootCSNumber = IntProperty(default=1, min=0)
Scene.ootCSImportName = StringProperty(
name="CS Name", description="Used to import a single cutscene, can be ``None``"
)


def cutscene_ops_unregister():
for cls in reversed(oot_cutscene_classes):
unregister_class(cls)

del Scene.ootCSImportName
del Scene.ootCSNumber
del Scene.ootCutsceneImportPath
del Scene.ootCutsceneExportPath
5 changes: 4 additions & 1 deletion fast64_internal/oot/cutscene/panels.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ def draw(self, context):

importBox = layout.box()
importBox.label(text="Cutscene Importer")
prop_split(importBox, context.scene, "ootCutsceneImportPath", "Import From")
prop_split(importBox, context.scene, "ootCSImportName", "Import")
prop_split(importBox, context.scene, "ootCutsceneImportPath", "From")

col = importBox.column()
if len(context.scene.ootCSImportName) == 0:
col.label(text="All Cutscenes will be imported.")
col.operator(OOT_ImportCutscene.bl_idname)


Expand Down
64 changes: 39 additions & 25 deletions fast64_internal/oot/tools/quick_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from ..f3d.properties import OOTDLImportSettings
from ..skeleton.properties import OOTSkeletonImportSettings
from ..animation.properties import OOTAnimImportSettingsProperty
from ..cutscene.importer import importCutsceneData


class QuickImportAborted(Exception):
Expand All @@ -15,6 +16,27 @@ def __init__(self, message):
self.message = message


def get_found_defs(path: Path, sym_name: str, sym_def_pattern: re.Pattern[str]):
all_found_defs: dict[Path, list[tuple[str, str]]] = dict()

for dirpath, _, filenames in os.walk(path):
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

return all_found_defs


def quick_import_exec(context: bpy.types.Context, sym_name: str):
sym_name = sym_name.strip()
if sym_name == "":
Expand All @@ -37,23 +59,14 @@ def quick_import_exec(context: bpy.types.Context, sym_name: str):

base_dir_p = Path(context.scene.ootDecompPath)
assets_objects_dir_p = base_dir_p / "assets" / "objects"
assets_scenes_dir_p = base_dir_p / "assets" / "scenes"
is_sym_object = True
all_found_defs = get_found_defs(assets_objects_dir_p, sym_name, sym_def_pattern)
if len(all_found_defs) == 0:
is_sym_object = False
all_found_defs = get_found_defs(assets_scenes_dir_p, sym_name, sym_def_pattern)

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
found_dir_p = assets_objects_dir_p if is_sym_object else assets_scenes_dir_p

# Ideally if for example sym_name was gLinkAdultHookshotTipDL,
# all_found_defs now contains:
Expand All @@ -66,24 +79,22 @@ def quick_import_exec(context: bpy.types.Context, sym_name: str):
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())
+ ", ".join(str(p.relative_to(found_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)}"
)
raise QuickImportAborted(f"Found several definitions of {sym_name} in {sym_file_p.relative_to(found_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]
folder_name = sym_file_p.relative_to(found_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.folder = folder_name
settings.actorOverlayName = ""
settings.isCustom = False
bpy.ops.object.oot_import_dl()
Expand All @@ -97,19 +108,22 @@ def quick_import_exec(context: bpy.types.Context, sym_name: str):
else:
settings.mode = "Generic"
settings.name = sym_name
settings.folder = object_name
settings.folder = folder_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
settings.folderName = folder_name
bpy.ops.object.oot_import_anim()
elif sym_def_type == "CutsceneData" and is_array:
path = assets_scenes_dir_p / folder_name / sym_file_p
bpy.context.scene.ootCSNumber = importCutsceneData(f"{path}", None, sym_name)
else:
raise QuickImportAborted(
f"Don't know how to import {sym_def_type}"
+ ("[]" if is_array else "")
+ f" (symbol found in {object_name})"
+ f" (symbol found in {folder_name})"
)

0 comments on commit 960a83f

Please sign in to comment.