[OOT/MM] Misc changes for MM (#555)

* gamedata update on load and game change

* cs index stuff

* gameeditormode and update panels

* format

* add versions

* comment MM game editor mode to avoid confusing users
This commit is contained in:
Yanis
2025-06-29 20:22:23 +01:00
committed by GitHub
parent f84d179de5
commit b77720fca7
20 changed files with 107 additions and 73 deletions
+7 -19
View File
@@ -1,9 +1,11 @@
import bpy
from bpy.utils import register_class, unregister_class
from bpy.path import abspath
from . import addon_updater_ops
from .fast64_internal.game_data import game_data
from .fast64_internal.utility import prop_split, multilineLabel, set_prop_if_in_data
from .fast64_internal.repo_settings import (
@@ -70,6 +72,7 @@ bl_info = {
gameEditorEnum = (
("SM64", "SM64", "Super Mario 64", 0),
("OOT", "OOT", "Ocarina Of Time", 1),
# ("MM", "MM", "Majora's Mask", 4),
("MK64", "MK64", "Mario Kart 64", 3),
("Homebrew", "Homebrew", "Homebrew", 2),
)
@@ -299,24 +302,6 @@ class UpgradeF3DMaterialsDialog(bpy.types.Operator):
return {"FINISHED"}
# def updateGameEditor(scene, context):
# if scene.currentGameEditorMode == 'SM64':
# sm64_panel_unregister()
# elif scene.currentGameEditorMode == 'Z64':
# oot_panel_unregister()
# else:
# raise PluginError("Unhandled game editor mode " + str(scene.currentGameEditorMode))
#
# if scene.gameEditorMode == 'SM64':
# sm64_panel_register()
# elif scene.gameEditorMode == 'Z64':
# oot_panel_register()
# else:
# raise PluginError("Unhandled game editor mode " + str(scene.gameEditorMode))
#
# scene.currentGameEditorMode = scene.gameEditorMode
class ExampleAddonPreferences(bpy.types.AddonPreferences, addon_updater_ops.AddonUpdaterPreferences):
bl_idname = __package__
@@ -371,6 +356,8 @@ def upgrade_scene_props_node():
@bpy.app.handlers.persistent
def after_load(_a, _b):
game_data.update(bpy.context.scene.gameEditorMode)
settings = bpy.context.scene.fast64.settings
if any(mat.is_f3d for mat in bpy.data.materials):
check_or_ask_color_management(bpy.context)
@@ -396,7 +383,7 @@ def set_game_defaults(scene: bpy.types.Scene, set_ucode=True):
elif scene.gameEditorMode == "MK64":
f3d_type = "F3DEX"
world_defaults = mk64_world_defaults
elif scene.gameEditorMode == "OOT":
elif scene.gameEditorMode in {"OOT", "MM"}:
f3d_type = "F3DEX2/LX2"
world_defaults = oot_world_defaults
elif scene.gameEditorMode == "MK64":
@@ -411,6 +398,7 @@ def set_game_defaults(scene: bpy.types.Scene, set_ucode=True):
def gameEditorUpdate(scene: bpy.types.Scene, _context):
game_data.update(scene.gameEditorMode)
set_game_defaults(scene)
+2 -2
View File
@@ -232,7 +232,7 @@ def update_draw_layer(self, context):
drawLayer = material.f3d_mat.draw_layer
if context.scene.gameEditorMode == "SM64":
drawLayer.oot = drawLayerSM64toOOT[drawLayer.sm64]
elif context.scene.gameEditorMode == "OOT":
elif context.scene.gameEditorMode in {"OOT", "MM"}:
if material.f3d_mat.draw_layer.oot == "Opaque":
if int(material.f3d_mat.draw_layer.sm64) > 4:
material.f3d_mat.draw_layer.sm64 = "1"
@@ -1053,7 +1053,7 @@ class F3DPanel(Panel):
def ui_draw_layer(self, material, layout, context):
if context.scene.gameEditorMode == "SM64":
prop_split(layout, material.f3d_mat.draw_layer, "sm64", "Draw Layer")
elif context.scene.gameEditorMode == "OOT":
elif context.scene.gameEditorMode in {"OOT", "MM"}:
prop_split(layout, material.f3d_mat.draw_layer, "oot", "Draw Layer")
def ui_misc(self, f3dMat: "F3DMaterialProperty", inputCol: UILayout, showCheckBox: bool) -> None:
+2 -2
View File
@@ -2010,7 +2010,7 @@ def parseVertexData(dlData: str, vertexDataName: str, f3dContext: F3DContext):
pathMatch = re.search(r'\#include\s*"([^"]*)"', data)
if pathMatch is not None:
path = pathMatch.group(1)
if bpy.context.scene.gameEditorMode == "OOT":
if bpy.context.scene.gameEditorMode in {"OOT", "MM"}:
path = str(oot_get_assets_path(path, check_exists=False))
data = readFile(f3dContext.getVTXPathFromInclude(path))
@@ -2116,7 +2116,7 @@ def parseTextureData(dlData, textureName, f3dContext, imageFormat, imageSize, wi
pathMatch = re.search(r'\#include\s*"(.*?)"', data, re.DOTALL)
if pathMatch is not None:
path = pathMatch.group(1)
is_oot = bpy.context.scene.gameEditorMode == "OOT"
is_oot = bpy.context.scene.gameEditorMode in {"OOT", "MM"}
if is_oot:
path = str(oot_get_assets_path(path, check_exists=False))
originalImage = bpy.data.images.load(f3dContext.getImagePathFromInclude(path, is_oot))
+2 -2
View File
@@ -256,7 +256,7 @@ def ootFlipbookAnimUpdate(self, armatureObj: bpy.types.Object, segment: str, ind
# we use a handler since update functions are not called when a property is animated.
@persistent
def flipbookAnimHandler(dummy):
if bpy.context.scene.gameEditorMode == "OOT":
if bpy.context.scene.gameEditorMode in {"OOT", "MM"}:
for obj in bpy.data.objects:
if obj.type == "ARMATURE":
# we only want to update texture on keyframed armatures.
@@ -291,7 +291,7 @@ class Flipbook_MaterialPanel(bpy.types.Panel):
mat = context.material
col = layout.column()
if context.scene.gameEditorMode == "OOT":
if context.scene.gameEditorMode in {"OOT", "MM"}:
checkFlipbookReference = ootFlipbookReferenceIsValid
drawFlipbookRequirementMessage = ootFlipbookRequirementMessage
else:
+15
View File
@@ -1,3 +1,5 @@
import bpy
from typing import Optional
@@ -11,9 +13,22 @@ class GameData:
self.update(game_editor_mode)
def update(self, game_editor_mode: str):
from .z64.utility import getObjectList
if game_editor_mode is not None and game_editor_mode in {"OOT", "MM"}:
self.z64.update(None, game_editor_mode, True)
# ensure `currentCutsceneIndex` is set to a correct value
if bpy.context.scene.gameEditorMode in {"OOT", "MM"}:
for scene_obj in bpy.data.objects:
scene_obj.ootAlternateSceneHeaders.currentCutsceneIndex = game_data.z64.cs_index_start
if scene_obj.type == "EMPTY" and scene_obj.ootEmptyType == "Scene":
room_obj_list = getObjectList(scene_obj.children_recursive, "EMPTY", "Room")
for room_obj in room_obj_list:
room_obj.ootAlternateRoomHeaders.currentCutsceneIndex = game_data.z64.cs_index_start
if game_editor_mode in {"OOT", "MM"} and game_editor_mode != self.z64.game:
raise ValueError(f"ERROR: Z64 game mismatch: {game_editor_mode}, {game_data.z64.game}")
+2 -2
View File
@@ -41,12 +41,12 @@ class SM64_Panel(bpy.types.Panel):
class OOT_Panel(bpy.types.Panel):
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "OOT"
bl_category = "Z64"
bl_options = {"DEFAULT_CLOSED"}
@classmethod
def poll(cls, context):
return context.scene.gameEditorMode == "OOT"
return context.scene.gameEditorMode in {"OOT", "MM"}
class MK64_Panel(bpy.types.Panel):
+12 -2
View File
@@ -3,6 +3,7 @@ import bpy
from pathlib import Path
from bpy.utils import register_class, unregister_class
from ..game_data import game_data
from ..utility import PluginError
from .scene.operators import scene_ops_register, scene_ops_unregister
@@ -83,6 +84,12 @@ oot_versions_items = [
("legacy", "Legacy", "Older Decomp Version", 10),
]
mm_versions_items = [
("Custom", "Custom", "Custom", 0),
("n64-us", "n64-us", "n64-us", 1),
("legacy", "Legacy", "Older Decomp Version", 2),
]
class OOT_Properties(bpy.types.PropertyGroup):
"""Global OOT Scene Properties found under scene.fast64.oot"""
@@ -101,13 +108,16 @@ class OOT_Properties(bpy.types.PropertyGroup):
animImportSettings: bpy.props.PointerProperty(type=OOTAnimImportSettingsProperty)
collisionExportSettings: bpy.props.PointerProperty(type=OOTCollisionExportSettings)
oot_version: bpy.props.EnumProperty(name="OoT Version", items=oot_versions_items, default="gc-eu-mq-dbg")
mm_version: bpy.props.EnumProperty(name="MM Version", items=mm_versions_items, default="n64-us")
oot_version_custom: bpy.props.StringProperty(name="Custom Version")
def get_extracted_path(self):
if self.oot_version == "legacy":
version = self.oot_version if game_data.z64.is_oot() else self.mm_version
if version == "legacy":
return "."
else:
return f"extracted/{self.oot_version if self.oot_version != 'Custom' else self.oot_version_custom}"
return f"extracted/{version if version != 'Custom' else self.oot_version_custom}"
def is_include_present(self, include_file: str):
decomp_path = Path(bpy.context.scene.ootDecompPath).resolve()
+3 -3
View File
@@ -17,7 +17,7 @@ class OOT_LinkAnimPanel(Panel):
@classmethod
def poll(cls, context):
return (
context.scene.gameEditorMode == "OOT"
context.scene.gameEditorMode in {"OOT", "MM"}
and hasattr(context, "object")
and context.object is not None
and isinstance(context.object.data, Armature)
@@ -33,8 +33,8 @@ class OOT_LinkAnimPanel(Panel):
class OOT_ExportAnimPanel(OOT_Panel):
bl_idname = "OOT_PT_export_anim"
bl_label = "OOT Animation Exporter"
bl_idname = "Z64_PT_export_anim"
bl_label = "Animation Exporter"
# called every frame
def draw(self, context):
+4 -4
View File
@@ -15,7 +15,7 @@ class OOT_CameraPosPanel(Panel):
@classmethod
def poll(cls, context):
return context.scene.gameEditorMode == "OOT" and isinstance(context.object.data, Camera)
return context.scene.gameEditorMode in {"OOT", "MM"} and isinstance(context.object.data, Camera)
def draw(self, context):
box = self.layout.box().column()
@@ -36,7 +36,7 @@ class OOT_CollisionPanel(Panel):
@classmethod
def poll(cls, context):
return context.scene.gameEditorMode == "OOT" and context.material is not None
return context.scene.gameEditorMode in {"OOT", "MM"} and context.material is not None
def draw(self, context):
box = self.layout.box().column()
@@ -46,8 +46,8 @@ class OOT_CollisionPanel(Panel):
class OOT_ExportCollisionPanel(OOT_Panel):
bl_idname = "OOT_PT_export_collision"
bl_label = "OOT Collision Exporter"
bl_idname = "Z64_PT_export_collision"
bl_label = "Collision Exporter"
# called every frame
def draw(self, context):
@@ -5,7 +5,7 @@ from .properties import CutsceneCmdCameraShotProperty, CutsceneCmdCameraShotPoin
class OOT_CSMotionCameraShotPanel(OOT_Panel):
bl_label = "Cutscene Motion Camera Shot Controls"
bl_idname = "OOT_PT_camera_shot_panel"
bl_idname = "Z64_PT_camera_shot_panel"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "object"
+4 -5
View File
@@ -7,19 +7,18 @@ from .operators import OOT_ExportCutscene, OOT_ExportAllCutscenes, OOT_ImportCut
class OoT_PreviewSettingsPanel(OOT_Panel):
bl_idname = "OOT_PT_preview_settings"
bl_label = "OOT CS Preview Settings"
bl_idname = "Z64_PT_preview_settings"
bl_label = "CS Preview Settings"
def draw(self, context):
context.scene.ootPreviewSettingsProperty.draw_props(self.layout)
class OOT_CutscenePanel(OOT_Panel):
bl_idname = "OOT_PT_export_cutscene"
bl_label = "OOT Cutscene Exporter"
bl_idname = "Z64_PT_export_cutscene"
bl_label = "Cutscene Exporter"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "OOT"
def draw(self, context):
layout = self.layout
+5 -5
View File
@@ -22,7 +22,7 @@ class OOT_DisplayListPanel(Panel):
@classmethod
def poll(cls, context):
return context.scene.gameEditorMode == "OOT" and (
return context.scene.gameEditorMode in {"OOT", "MM"} and (
context.object is not None and isinstance(context.object.data, Mesh)
)
@@ -58,7 +58,7 @@ class OOT_MaterialPanel(Panel):
@classmethod
def poll(cls, context):
return context.material is not None and context.scene.gameEditorMode == "OOT"
return context.material is not None and context.scene.gameEditorMode in {"OOT", "MM"}
def draw(self, context):
layout = self.layout
@@ -91,7 +91,7 @@ class OOT_DrawLayersPanel(Panel):
@classmethod
def poll(cls, context):
return context.scene.gameEditorMode == "OOT"
return context.scene.gameEditorMode in {"OOT", "MM"}
def draw(self, context):
world = context.scene.world
@@ -102,8 +102,8 @@ class OOT_DrawLayersPanel(Panel):
class OOT_ExportDLPanel(OOT_Panel):
bl_idname = "OOT_PT_export_dl"
bl_label = "OOT DL Exporter"
bl_idname = "Z64_PT_export_dl"
bl_label = "DL Exporter"
# called every frame
def draw(self, context):
+7 -4
View File
@@ -1,14 +1,16 @@
from bpy.utils import register_class, unregister_class
from bpy.props import StringProperty, FloatProperty, BoolProperty
from bpy.props import StringProperty, FloatProperty
from bpy.types import Scene
from ..game_data import game_data
from ..utility import prop_split
from ..render_settings import on_update_render_settings
from ..panels import OOT_Panel
class OOT_FileSettingsPanel(OOT_Panel):
bl_idname = "OOT_PT_file_settings"
bl_label = "OOT File Settings"
bl_idname = "Z64_PT_file_settings"
bl_label = "Workspace Settings"
bl_options = set() # default to being open
# called every frame
@@ -19,7 +21,8 @@ class OOT_FileSettingsPanel(OOT_Panel):
prop_split(col, context.scene, "ootDecompPath", "Decomp Path")
prop_split(col, context.scene.fast64.oot, "oot_version", "OoT Version")
version = "oot_version" if game_data.z64.is_oot() else "mm_version"
prop_split(col, context.scene.fast64.oot, version, "Game Version")
if context.scene.fast64.oot.oot_version == "Custom":
prop_split(col, context.scene.fast64.oot, "oot_version_custom", "Custom Version")
+3 -1
View File
@@ -117,7 +117,9 @@ class OOTObjectPanel(bpy.types.Panel):
@classmethod
def poll(cls, context):
return context.scene.gameEditorMode == "OOT" and (context.object is not None and context.object.type == "EMPTY")
return context.scene.gameEditorMode in {"OOT", "MM"} and (
context.object is not None and context.object.type == "EMPTY"
)
def draw(self, context):
prop_split(self.layout, context.scene, "gameEditorMode", "Game")
+15 -6
View File
@@ -1,6 +1,8 @@
import bpy
from bpy.types import PropertyGroup, UILayout, Image, Object
from bpy.types import PropertyGroup, UILayout, Image, Object, Context
from bpy.utils import register_class, unregister_class
from ...utility import prop_split
from ...game_data import game_data
from ..collection_utility import drawCollectionOps, drawAddButton
@@ -150,9 +152,9 @@ class OOTRoomHeaderProperty(PropertyGroup):
if not self.expandTab:
return
if headerIndex is not None and headerIndex > 3:
drawCollectionOps(layout, headerIndex - 4, "Room", None, objName)
drawCollectionOps(layout, headerIndex - game_data.z64.cs_index_start, "Room", None, objName)
if headerIndex is not None and headerIndex > 0 and headerIndex < 4:
if headerIndex is not None and headerIndex > 0 and headerIndex < game_data.z64.cs_index_start:
layout.prop(self, "usePreviousHeader", text="Use Previous Header")
if self.usePreviousHeader:
return
@@ -238,6 +240,13 @@ class OOTRoomHeaderProperty(PropertyGroup):
drawAddButton(objBox, len(self.objectList), "Object", headerIndex, objName)
def update_cutscene_index(self: "OOTAlternateRoomHeaderProperty", context: Context):
if self.currentCutsceneIndex < game_data.z64.cs_index_start:
self.currentCutsceneIndex = game_data.z64.cs_index_start
onHeaderMenuTabChange(self, context)
class OOTAlternateRoomHeaderProperty(PropertyGroup):
childNightHeader: PointerProperty(name="Child Night Header", type=OOTRoomHeaderProperty)
adultDayHeader: PointerProperty(name="Adult Day Header", type=OOTRoomHeaderProperty)
@@ -245,7 +254,7 @@ class OOTAlternateRoomHeaderProperty(PropertyGroup):
cutsceneHeaders: CollectionProperty(type=OOTRoomHeaderProperty)
headerMenuTab: EnumProperty(name="Header Menu", items=ootEnumHeaderMenu, update=onHeaderMenuTabChange)
currentCutsceneIndex: IntProperty(min=4, default=4, update=onHeaderMenuTabChange)
currentCutsceneIndex: IntProperty(default=1, update=update_cutscene_index)
def draw_props(self, layout: UILayout, objName: str):
headerSetup = layout.column()
@@ -263,8 +272,8 @@ class OOTAlternateRoomHeaderProperty(PropertyGroup):
prop_split(headerSetup, self, "currentCutsceneIndex", "Cutscene Index")
drawAddButton(headerSetup, len(self.cutsceneHeaders), "Room", None, objName)
index = self.currentCutsceneIndex
if index - 4 < len(self.cutsceneHeaders):
self.cutsceneHeaders[index - 4].draw_props(headerSetup, None, index, objName)
if index - game_data.z64.cs_index_start < len(self.cutsceneHeaders):
self.cutsceneHeaders[index - game_data.z64.cs_index_start].draw_props(headerSetup, None, index, objName)
else:
headerSetup.label(text="No cutscene header for this index.", icon="QUESTION")
+2 -2
View File
@@ -23,8 +23,8 @@ from .operators import (
class OOT_ExportScenePanel(OOT_Panel):
bl_idname = "OOT_PT_export_level"
bl_label = "OOT Scene Exporter"
bl_idname = "Z64_PT_export_level"
bl_label = "Scene Exporter"
def drawSceneSearchOp(self, layout: UILayout, enumValue: str, opName: str):
searchBox = layout.box().row()
+14 -6
View File
@@ -1,5 +1,6 @@
import bpy
from bpy.types import PropertyGroup, Object, Light, UILayout, Scene
from bpy.types import PropertyGroup, Object, Light, UILayout, Scene, Context
from bpy.props import (
EnumProperty,
IntProperty,
@@ -324,9 +325,9 @@ class OOTSceneHeaderProperty(PropertyGroup):
if not self.expandTab:
return
if headerIndex is not None and headerIndex > 3:
drawCollectionOps(layout, headerIndex - 4, "Scene", None, objName)
drawCollectionOps(layout, headerIndex - game_data.z64.cs_index_start, "Scene", None, objName)
if headerIndex is not None and headerIndex > 0 and headerIndex < 4:
if headerIndex is not None and headerIndex > 0 and headerIndex < game_data.z64.cs_index_start:
layout.prop(self, "usePreviousHeader", text="Use Previous Header")
if self.usePreviousHeader:
return
@@ -406,6 +407,13 @@ class OOTSceneHeaderProperty(PropertyGroup):
drawAddButton(exitBox, len(self.exitList), "Exit", headerIndex, objName)
def update_cutscene_index(self: "OOTAlternateSceneHeaderProperty", context: Context):
if self.currentCutsceneIndex < game_data.z64.cs_index_start:
self.currentCutsceneIndex = game_data.z64.cs_index_start
onHeaderMenuTabChange(self, context)
class OOTAlternateSceneHeaderProperty(PropertyGroup):
childNightHeader: PointerProperty(name="Child Night Header", type=OOTSceneHeaderProperty)
adultDayHeader: PointerProperty(name="Adult Day Header", type=OOTSceneHeaderProperty)
@@ -413,7 +421,7 @@ class OOTAlternateSceneHeaderProperty(PropertyGroup):
cutsceneHeaders: CollectionProperty(type=OOTSceneHeaderProperty)
headerMenuTab: EnumProperty(name="Header Menu", items=ootEnumHeaderMenu, update=onHeaderMenuTabChange)
currentCutsceneIndex: IntProperty(min=4, default=4, update=onHeaderMenuTabChange)
currentCutsceneIndex: IntProperty(default=1, update=update_cutscene_index)
def draw_props(self, layout: UILayout, objName: str):
headerSetup = layout.column()
@@ -431,8 +439,8 @@ class OOTAlternateSceneHeaderProperty(PropertyGroup):
prop_split(headerSetup, self, "currentCutsceneIndex", "Cutscene Index")
drawAddButton(headerSetup, len(self.cutsceneHeaders), "Scene", None, objName)
index = self.currentCutsceneIndex
if index - 4 < len(self.cutsceneHeaders):
self.cutsceneHeaders[index - 4].draw_props(headerSetup, None, index, objName)
if index - game_data.z64.cs_index_start < len(self.cutsceneHeaders):
self.cutsceneHeaders[index - game_data.z64.cs_index_start].draw_props(headerSetup, None, index, objName)
else:
headerSetup.label(text="No cutscene header for this index.", icon="QUESTION")
+4 -4
View File
@@ -17,7 +17,7 @@ class OOT_SkeletonPanel(Panel):
@classmethod
def poll(cls, context):
return (
context.scene.gameEditorMode == "OOT"
context.scene.gameEditorMode in {"OOT", "MM"}
and hasattr(context, "object")
and context.object is not None
and isinstance(context.object.data, Armature)
@@ -43,7 +43,7 @@ class OOT_BonePanel(Panel):
@classmethod
def poll(cls, context):
return context.scene.gameEditorMode == "OOT" and context.bone is not None
return context.scene.gameEditorMode in {"OOT", "MM"} and context.bone is not None
# called every frame
def draw(self, context):
@@ -53,8 +53,8 @@ class OOT_BonePanel(Panel):
class OOT_ExportSkeletonPanel(OOT_Panel):
bl_idname = "OOT_PT_export_skeleton"
bl_label = "OOT Skeleton Exporter"
bl_idname = "Z64_PT_export_skeleton"
bl_label = "Skeleton Exporter"
# called every frame
def draw(self, context):
+1 -1
View File
@@ -16,7 +16,7 @@ class OOTSplinePanel(Panel):
@classmethod
def poll(cls, context):
return context.scene.gameEditorMode == "OOT" and (
return context.scene.gameEditorMode in {"OOT", "MM"} and (
context.object is not None and type(context.object.data) == Curve
)
+2 -2
View File
@@ -13,8 +13,8 @@ from .operators import (
class OoT_ToolsPanel(OOT_Panel):
bl_idname = "OOT_PT_tools"
bl_label = "OOT Tools"
bl_idname = "Z64_PT_tools"
bl_label = "Tools"
def draw(self, context):
col = self.layout.column()