feat: Add VRM Blender addon with complete import/export functionality
- Add core VRM addon infrastructure with manifest and registration - Add common utilities module with file system, logging, and conversion helpers - Add human bone mapper with support for multiple rigging standards (Mixamo, MMD, Unreal, Rigify, etc.) - Add VRM 0.x and 1.x format support with property groups and handlers - Add editor UI panels for VRM metadata, spring bones, and MToon materials - Add exporter with glTF2 extension support for VRM format serialization - Add importer with scene reconstruction and armature generation - Add MToon shader support with auto-setup and material migration - Add spring bone physics simulation with constraint handling - Add node constraint editor for advanced rigging control - Add comprehensive validation and error handling with user dialogs - Add scene watcher for real-time property synchronization - Add workspace management and preference system - Include Python cache files and Blender manifest configuration - This is the initial commit establishing the complete VRM addon ecosystem for Blender
This commit is contained in:
161
common/version.py
Normal file
161
common/version.py
Normal file
@@ -0,0 +1,161 @@
|
||||
# SPDX-License-Identifier: MIT OR GPL-3.0-or-later
|
||||
import platform
|
||||
from dataclasses import dataclass
|
||||
from sys import float_info
|
||||
from typing import Optional
|
||||
|
||||
import bpy
|
||||
from bpy.app.translations import pgettext
|
||||
|
||||
from .blender_manifest import BlenderManifest
|
||||
from .logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Cache:
|
||||
use: bool
|
||||
last_blender_restart_required: bool
|
||||
last_blender_manifest_modification_time: float
|
||||
initial_blender_manifest_content: bytes
|
||||
|
||||
|
||||
cache = Cache(
|
||||
use=False,
|
||||
last_blender_restart_required=False,
|
||||
last_blender_manifest_modification_time=0.0,
|
||||
initial_blender_manifest_content=BlenderManifest.default_blender_manifest_path().read_bytes(),
|
||||
)
|
||||
|
||||
|
||||
def clear_addon_version_cache() -> Optional[float]:
|
||||
cache.use = False
|
||||
return None
|
||||
|
||||
|
||||
def trigger_clear_addon_version_cache() -> None:
|
||||
if tuple(bpy.app.version) >= (4, 2):
|
||||
return
|
||||
if bpy.app.timers.is_registered(clear_addon_version_cache):
|
||||
return
|
||||
bpy.app.timers.register(clear_addon_version_cache, first_interval=0.5)
|
||||
|
||||
|
||||
def min_unsupported_blender_major_minor_version() -> Optional[tuple[int, int]]:
|
||||
blender_version_max = BlenderManifest.read().blender_version_max
|
||||
if blender_version_max is None:
|
||||
return None
|
||||
return (blender_version_max[0], blender_version_max[1])
|
||||
|
||||
|
||||
def get_addon_version() -> tuple[int, int, int]:
|
||||
return BlenderManifest.read().version
|
||||
|
||||
|
||||
def blender_restart_required() -> bool:
|
||||
if tuple(bpy.app.version) >= (4, 2):
|
||||
return False
|
||||
|
||||
if cache.use:
|
||||
return cache.last_blender_restart_required
|
||||
|
||||
cache.use = True
|
||||
|
||||
if cache.last_blender_restart_required:
|
||||
return True
|
||||
|
||||
blender_manifest_path = BlenderManifest.default_blender_manifest_path()
|
||||
blender_manifest_modification_time = blender_manifest_path.stat().st_mtime
|
||||
if (
|
||||
abs(
|
||||
cache.last_blender_manifest_modification_time
|
||||
- blender_manifest_modification_time
|
||||
)
|
||||
< float_info.epsilon
|
||||
):
|
||||
return False
|
||||
|
||||
cache.last_blender_manifest_modification_time = blender_manifest_modification_time
|
||||
|
||||
blender_manifest_content = blender_manifest_path.read_bytes()
|
||||
if blender_manifest_content == cache.initial_blender_manifest_content:
|
||||
return False
|
||||
|
||||
cache.last_blender_restart_required = True
|
||||
return True
|
||||
|
||||
|
||||
def stable_release() -> bool:
|
||||
if bpy.app.version_cycle == "release":
|
||||
return True
|
||||
|
||||
# Microsoft Store distributes RC versions of 3.3.11 and 3.6.3 as
|
||||
# release versions.
|
||||
return platform.system() == "Windows" and bpy.app.version_cycle == "rc"
|
||||
|
||||
|
||||
def supported() -> bool:
|
||||
v = min_unsupported_blender_major_minor_version()
|
||||
if v is None:
|
||||
return True
|
||||
return bpy.app.version[:2] < v
|
||||
|
||||
|
||||
def preferences_warning_message() -> Optional[str]:
|
||||
if blender_restart_required():
|
||||
return pgettext(
|
||||
"The VRM add-on has been updated."
|
||||
+ " Please restart Blender to apply the changes."
|
||||
)
|
||||
if not stable_release():
|
||||
return pgettext(
|
||||
"VRM add-on is not compatible with Blender {blender_version_cycle}."
|
||||
).format(blender_version_cycle=bpy.app.version_cycle.capitalize())
|
||||
if not supported():
|
||||
return pgettext(
|
||||
"The installed VRM add-on is not compatible with Blender {blender_version}."
|
||||
+ " Please upgrade the add-on.",
|
||||
).format(blender_version=".".join(map(str, bpy.app.version[:2])))
|
||||
return None
|
||||
|
||||
|
||||
def panel_warning_message() -> Optional[str]:
|
||||
if blender_restart_required():
|
||||
return pgettext(
|
||||
"The VRM add-on has been\n"
|
||||
+ "updated. Please restart Blender\n"
|
||||
+ "to apply the changes."
|
||||
)
|
||||
if not stable_release():
|
||||
return pgettext(
|
||||
"VRM add-on is\n"
|
||||
+ "not compatible with\n"
|
||||
+ "Blender {blender_version_cycle}."
|
||||
).format(blender_version_cycle=bpy.app.version_cycle.capitalize())
|
||||
if not supported():
|
||||
return pgettext(
|
||||
"The installed VRM add-\n"
|
||||
+ "on is not compatible with\n"
|
||||
+ "Blender {blender_version}. Please update."
|
||||
).format(blender_version=".".join(map(str, bpy.app.version[:2])))
|
||||
return None
|
||||
|
||||
|
||||
def validation_warning_message() -> Optional[str]:
|
||||
if blender_restart_required():
|
||||
return pgettext(
|
||||
"The VRM add-on has been updated."
|
||||
+ " Please restart Blender to apply the changes."
|
||||
)
|
||||
if not stable_release():
|
||||
return pgettext(
|
||||
"VRM add-on is not compatible with Blender {blender_version_cycle}."
|
||||
+ " The VRM may not be exported correctly.",
|
||||
).format(blender_version_cycle=bpy.app.version_cycle.capitalize())
|
||||
if not supported():
|
||||
return pgettext(
|
||||
"The installed VRM add-on is not compatible with Blender {blender_version}."
|
||||
+ " The VRM may not be exported correctly."
|
||||
).format(blender_version=".".join(map(str, bpy.app.version)))
|
||||
return None
|
||||
Reference in New Issue
Block a user