Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fast64_internal/data/z64/actor_data.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from os import path
from dataclasses import dataclass
from pathlib import Path

from .common import Z64_BaseElement, get_xml_root


Expand Down Expand Up @@ -36,7 +36,7 @@ class Z64_ActorData:

def __init__(self, game: str):
# Path to the ``ActorList.xml`` file
xml_path = Path(f"{path.dirname(path.abspath(__file__))}/xml/{game.lower()}_actor_list.xml")
xml_path = Path(__file__).resolve().parent / "xml" / f"{game.lower()}_actor_list.xml"
actor_root = get_xml_root(xml_path.resolve())

# general actor list
Expand Down
4 changes: 3 additions & 1 deletion fast64_internal/data/z64/common.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from xml.etree.ElementTree import parse as parseXML, Element
from dataclasses import dataclass
from pathlib import Path


@dataclass
Expand All @@ -10,9 +11,10 @@ class Z64_BaseElement:
index: int


def get_xml_root(xmlPath: str) -> Element:
def get_xml_root(xmlPath: Path) -> Element:
"""Parse an XML file and return its root element"""
try:
assert xmlPath.exists()
return parseXML(xmlPath).getroot()
except:
from ...utility import PluginError
Expand Down
4 changes: 2 additions & 2 deletions fast64_internal/data/z64/enum_data.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from dataclasses import dataclass, field
from os import path
from pathlib import Path

from .common import Z64_BaseElement, get_xml_root


Expand Down Expand Up @@ -72,7 +72,7 @@ def __init__(self, game: str):
self.enumDataList: list[Z64_EnumElement] = []

# Path to the ``EnumData.xml`` file
xml_path = Path(f"{path.dirname(path.abspath(__file__))}/xml/{game.lower()}_enum_data.xml")
xml_path = Path(__file__).resolve().parent / "xml" / f"{game.lower()}_enum_data.xml"
enum_data_root = get_xml_root(xml_path.resolve())

for enum in enum_data_root.iterfind("Enum"):
Expand Down
4 changes: 2 additions & 2 deletions fast64_internal/data/z64/object_data.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from dataclasses import dataclass
from os import path
from pathlib import Path

from ...utility import PluginError
from .common import Z64_BaseElement, get_xml_root

Expand All @@ -20,7 +20,7 @@ def __init__(self, game: str):
self.objectList: list[Z64_ObjectElement] = []

# Path to the ``ObjectList.xml`` file
xml_path = Path(f"{path.dirname(path.abspath(__file__))}/xml/{game.lower()}_object_list.xml")
xml_path = Path(__file__).resolve().parent / "xml" / f"{game.lower()}_object_list.xml"
object_root = get_xml_root(xml_path.resolve())

for obj in object_root.iterfind("Object"):
Expand Down
20 changes: 15 additions & 5 deletions fast64_internal/f3d/f3d_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1970,6 +1970,16 @@ def parseF3D(
processedDLName = f3dContext.processDLName(dlName)
if processedDLName is not None:
dlCommands = parseDLData(dlData, processedDLName)

# some commands in OoT are using macros to set width and height values
if bpy.context.scene.gameEditorMode in {"OOT", "MM"}:
for command in dlCommands:
for i, param in enumerate(command.params):
if "_WIDTH" in param or "_HEIGHT" in param:
value_match = re.search(rf"\#define\s?{param}\s?(\d*)", dlData, re.DOTALL)
assert value_match is not None, f"can't find {repr(param)}"
command.params[i] = value_match.group(1)

f3dContext.processCommands(dlData, processedDLName, dlCommands)

if callClearMaterial:
Expand Down Expand Up @@ -2262,12 +2272,12 @@ def parseMacroArgs(data: str):
return params


def getImportData(filepaths):
def getImportData(filepaths: list[Path | str]):
data = ""
for path in filepaths:
if os.path.exists(path):
data += readFile(path)

for base_path in filepaths:
path = Path(base_path) if isinstance(base_path, str) else base_path
if path.exists():
data += path.read_text()
return data


Expand Down
11 changes: 7 additions & 4 deletions fast64_internal/utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -2063,14 +2063,14 @@ def as_posix(path: Path) -> str:
def oot_get_assets_path(base_path: str, check_exists: bool = True, use_decomp_path: bool = True):
# get the extracted path
extracted = bpy.context.scene.fast64.oot.get_extracted_path()
decomp_path = bpy.context.scene.ootDecompPath if use_decomp_path else "."
decomp_path = bpy.context.scene.fast64.oot.get_decomp_path()

# get the file's path
file_path = Path(f"{decomp_path}/{base_path}").resolve()
file_path = Path(f"{decomp_path if use_decomp_path else '.'}/{base_path}").resolve()

# check if the path exists
if not file_path.exists():
file_path = Path(f"{bpy.context.scene.ootDecompPath}/{extracted}/{base_path}").resolve()
file_path = Path(f"{decomp_path}/{extracted}/{base_path}").resolve()

# if it doesn't check if the extracted path exists (we want to skip that for PNG files)
if check_exists and not file_path.exists():
Expand All @@ -2092,7 +2092,10 @@ def get_include_data(include: str, strip: bool = False):
include = include.replace("\n", "").removeprefix("#include ").replace('"', "")

if bpy.context.scene.gameEditorMode in {"OOT", "MM"}:
file_path = oot_get_assets_path(include)
file_path: Path = bpy.context.scene.fast64.oot.get_decomp_path() / include

if not file_path.exists():
file_path = oot_get_assets_path(include)
else:
raise PluginError(f"ERROR: game not supported ({bpy.context.scene.gameEditorMode})")

Expand Down
32 changes: 30 additions & 2 deletions fast64_internal/z64/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import bpy

from typing import Optional
from pathlib import Path
from bpy.utils import register_class, unregister_class

Expand All @@ -13,7 +14,7 @@
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 .collection_utility import collections_register, collections_unregister
from .utility import setAllActorsVisibility
from .utility import PathUtils, setAllActorsVisibility
from .file_settings import file_register, file_unregister
from .collision.properties import OOTCollisionExportSettings

Expand Down Expand Up @@ -146,8 +147,16 @@ def get_extracted_path(self):
else:
return f"extracted/{version if version != 'Custom' else self.oot_version_custom}"

def get_decomp_path(self):
decomp_path = Path(bpy.path.abspath(bpy.context.scene.ootDecompPath)).resolve()

if not decomp_path.exists():
raise PluginError(f"ERROR: invalid decomp path ('{decomp_path}').")

return decomp_path

def is_include_present(self, include_file: str):
decomp_path = Path(bpy.context.scene.ootDecompPath).resolve()
decomp_path = self.get_decomp_path()

if not decomp_path.exists():
raise PluginError(f"ERROR: invalid decomp path ('{decomp_path}').")
Expand All @@ -161,6 +170,25 @@ def is_globalh_present(self):
def is_z64sceneh_present(self):
return self.is_include_present("z64scene.h")

def get_assets_path(
self,
is_import: bool,
folder_name: str,
expected_folder: Optional[str] = None,
check_extracted: bool = True,
check_file: bool = False,
with_decomp_path: bool = False,
):
with PathUtils(is_import, self.get_decomp_path(), None, folder_name, False) as path_utils:
path = path_utils.get_assets_path(
expected_folder=expected_folder,
check_extracted=check_extracted,
check_file=check_file,
with_decomp_path=with_decomp_path,
)

return str(path)

useDecompFeatures: bpy.props.BoolProperty(
name="Use decomp for export", description="Use names and macros from decomp when exporting", default=True
)
Expand Down
42 changes: 24 additions & 18 deletions fast64_internal/z64/animation/importer/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
import bpy
import re
import math

from bpy.types import Object
from pathlib import Path

from ....utility import PluginError, hexOrDecInt, get_include_data, removeComments
from ....f3d.f3d_parser import getImportData
from ...model_classes import ootGetIncludedAssetData
Expand All @@ -26,10 +30,10 @@ def binangToRadians(value):
return math.radians(value * 360 / (2**16))


def getFrameData(filepath: str, animData: str, frameDataName: str):
matchResult = re.search(re.escape(frameDataName) + "\s*\[.*?\]\s*=\s*\{([^\}]*)\}", animData, re.DOTALL)
def getFrameData(filepath: Path, animData: str, frameDataName: str):
matchResult = re.search(re.escape(frameDataName) + r"\s*\[.*?\]\s*=\s*\{([^\}]*)\}", animData, re.DOTALL)
if matchResult is None:
raise PluginError("Cannot find animation frame data named " + frameDataName + " in " + filepath)
raise PluginError(f"Cannot find animation frame data named {frameDataName} in {filepath}")
data = matchResult.group(1)

if "#include" in data:
Expand All @@ -45,33 +49,35 @@ def getFrameData(filepath: str, animData: str, frameDataName: str):
return frameData


def getJointIndices(filepath, animData, jointIndicesName):
matchResult = re.search(re.escape(jointIndicesName) + "\s*\[\s*[0-9]*\s*\]\s*=\s*\{([^;]*);", animData, re.DOTALL)
def getJointIndices(filepath: Path, animData: str, jointIndicesName: str):
matchResult = re.search(re.escape(jointIndicesName) + r"\s*\[\s*[0-9]*\s*\]\s*=\s*\{([^;]*);", animData, re.DOTALL)
if matchResult is None:
raise PluginError("Cannot find animation joint indices data named " + jointIndicesName + " in " + filepath)
raise PluginError(f"Cannot find animation joint indices data named {jointIndicesName} in {filepath}")
data = matchResult.group(1)

if "#include" in data:
data = get_include_data(data.removesuffix("}"), strip=True)

jointIndicesData = [
[hexOrDecInt(match.group(i)) for i in range(1, 4)]
for match in re.finditer("\{([^,\}]*),([^,\}]*),([^,\}]*)\s*,?\s*\}", data, re.DOTALL)
for match in re.finditer(r"\{([^,\}]*),([^,\}]*),([^,\}]*)\s*,?\s*\}", data, re.DOTALL)
]

return jointIndicesData


def ootImportNonLinkAnimationC(armatureObj, filepath, animName, actorScale, isCustomImport: bool):
def ootImportNonLinkAnimationC(
armatureObj: Object, filepath: Path, animName: str, actorScale: float, isCustomImport: bool
):
animData = getImportData([filepath])
if not isCustomImport:
basePath = bpy.path.abspath(bpy.context.scene.ootDecompPath)
basePath = bpy.context.scene.fast64.oot.get_decomp_path()
animData = ootGetIncludedAssetData(basePath, [filepath], animData) + animData

matchResult = re.search(re.escape(animName) + r"\s*=\s*\{(.*?)\}\s*;", animData, re.DOTALL | re.MULTILINE)

if matchResult is None:
raise PluginError("Cannot find definition named " + animName + " in " + filepath)
raise PluginError(f"Cannot find definition named {animName} in {filepath}")

if "#include" in matchResult.group(1):
anim_data = removeComments(get_include_data(matchResult.group(1))).replace("\n", "").replace(" ", "")
Expand All @@ -88,7 +94,7 @@ def ootImportNonLinkAnimationC(armatureObj, filepath, animName, actorScale, isCu
anim_data,
)
if matchResult is None:
raise PluginError("Cannot find animation named " + animName + " in " + filepath)
raise PluginError(f"Cannot find animation named {animName} in {filepath}")
frameCount = hexOrDecInt(matchResult.group(1).strip())
frameDataName = matchResult.group(2).strip()
jointIndicesName = matchResult.group(3).strip()
Expand Down Expand Up @@ -176,19 +182,19 @@ def ootImportNonLinkAnimationC(armatureObj, filepath, animName, actorScale, isCu
# animName is header name.
# numLimbs = 21 for link.
def ootImportLinkAnimationC(
armatureObj: bpy.types.Object,
animHeaderFilepath: str,
animFilepath: str,
armatureObj: Object,
animHeaderFilepath: Path,
animFilepath: Path,
animHeaderName: str,
actorScale: float,
numLimbs: int,
isCustomImport: bool,
):
header_data = getImportData([animFilepath.replace(".c", ".h")])
header_data = getImportData([animFilepath.with_suffix(".h")])
animHeaderData = getImportData([animHeaderFilepath])
animData = getImportData([animFilepath])
if not isCustomImport:
basePath = bpy.path.abspath(bpy.context.scene.ootDecompPath)
basePath = bpy.context.scene.fast64.oot.get_decomp_path()
animHeaderData = ootGetIncludedAssetData(basePath, [animHeaderFilepath], animHeaderData) + animHeaderData
animData = ootGetIncludedAssetData(basePath, [animFilepath], animData) + animData

Expand All @@ -197,7 +203,7 @@ def ootImportLinkAnimationC(
)

if matchResult is None:
raise PluginError("Cannot find definition named " + animHeaderName + " in " + animHeaderFilepath)
raise PluginError(f"Cannot find definition named {animHeaderName} in {animHeaderFilepath}")

if "#include" in matchResult.group(1):
anim_data = removeComments(get_include_data(matchResult.group(1))).replace("\n", "").replace(" ", "")
Expand All @@ -211,7 +217,7 @@ def ootImportLinkAnimationC(
anim_data,
)
if matchResult is None:
raise PluginError("Cannot find animation named " + animHeaderName + " in " + animHeaderFilepath)
raise PluginError(f"Cannot find animation named {animHeaderName} in {animHeaderFilepath}")

frame_count_raw = matchResult.group(1).strip()

Expand Down
Loading