Browse Source

Migrate duplicated bounds properties.

This migrates duplicated bounds properties (i.e. those *NOT* found on
the collision modifier) to be stored on the collision modifier. This can
potentially be a lossy process if there are multiple conflicting bounds
property values for a single object. This may result in some Ages having
"new" bugs appear, but, really, they were only working by sheer dumb
luck before. It's better this way.
pull/415/head
Adam Johnson 6 months ago
parent
commit
0d84b78762
Signed by: Hoikas
GPG Key ID: 0B6515D6FF6F271E
  1. 45
      korman/enum_props.py
  2. 53
      korman/nodes/node_conditions.py
  3. 4
      korman/properties/modifiers/base.py
  4. 15
      korman/properties/modifiers/region.py

45
korman/enum_props.py

@ -18,6 +18,7 @@ from __future__ import annotations
from bpy.props import *
from typing import *
import warnings
# These are the kinds of physical bounds Plasma can work with.
# This sequence is acceptable in any EnumProperty
@ -54,9 +55,53 @@ def bounds(physics_attr: Optional[str] = None, store_on_collider: bool = True, *
if store_on_collider:
kwargs["get"] = _get_bounds(physics_attr)
kwargs["set"] = _set_bounds(physics_attr)
else:
warnings.warn("Storing bounds properties outside of the collision modifier is deprecated.", category=DeprecationWarning)
if "default" not in kwargs:
kwargs["default"] = "hull"
return EnumProperty(
items=_bounds_types,
**kwargs
)
def upgrade_bounds(bl, bounds_attr: str) -> None:
# Only perform this process if the property has a value. Otherwise, we'll
# wind up blowing away the collision modifier's settings with nonsense.
if not bl.is_property_set(bounds_attr):
return
# Before we unregister anything, grab a copy of what the collision modifier currently thinks.
bounds_value_curr = getattr(bl, bounds_attr)
# So, here's the deal. If someone has been playing with nodes and changed the bounds type,
# Blender will think the property has been set, even if they wound up with the property
# at the default value. I don't know that we can really trust the default in the property
# definition to be the same as the old default (they shouldn't be different, but let's be safe).
# So, let's apply rough justice. If the destination property thinks it's a triangle mesh, we
# don't need to blow that away - it's a very specific non default setting.
if bounds_value_curr == "trimesh":
return
# Unregister the new/correct proxy bounds property (with getter/setter) and re-register
# the property without the proxy functions to get the old value. Reregister the new property
# again and set it.
cls = bl.__class__
prop_func, prop_def = getattr(cls, bounds_attr)
RemoveProperty(cls, attr=bounds_attr)
del prop_def["attr"]
# Remove the things we don't want in a copy to prevent hosing the new property.
old_prop_def = dict(prop_def)
del old_prop_def["get"]
del old_prop_def["set"]
setattr(cls, bounds_attr, prop_func(**old_prop_def))
bounds_value_new = getattr(bl, bounds_attr)
# Re-register new property.
RemoveProperty(cls, attr=bounds_attr)
setattr(cls, bounds_attr, prop_func(**prop_def))
# Only set the property if the value different to avoid thrashing and log spam.
if bounds_value_curr != bounds_value_new:
print(f"Stashing bounds property: [{bl.name}] ({cls.__name__}) {bounds_value_curr} -> {bounds_value_new}") # TEMP
setattr(bl, bounds_attr, bounds_value_new)

53
korman/nodes/node_conditions.py

@ -23,9 +23,10 @@ from typing import *
from .. import enum_props
from .node_core import *
from .node_deprecated import PlasmaVersionedNode
from .. import idprops
class PlasmaClickableNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.types.Node):
class PlasmaClickableNode(idprops.IDPropObjectMixin, PlasmaVersionedNode, bpy.types.Node):
bl_category = "CONDITIONS"
bl_idname = "PlasmaClickableNode"
bl_label = "Clickable"
@ -40,9 +41,9 @@ class PlasmaClickableNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.types.N
poll=idprops.poll_mesh_objects)
bounds = enum_props.bounds(
"clickable_object", store_on_collider=False,
"clickable_object",
name="Bounds",
description="Clickable's bounds (NOTE: only used if your clickable is not a collider)",
description="Clickable's bounds",
default="hull"
)
@ -154,8 +155,20 @@ class PlasmaClickableNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.types.N
def _idprop_mapping(cls):
return {"clickable_object": "clickable"}
@property
def latest_version(self):
return 2
def upgrade(self):
# In version 1 of this node, the bounds type was stored on this node. This could
# be overridden by whatever was in the collision modifier. Version 2 changes the
# bounds property to proxy to the collision modifier's bounds settings.
if self.version == 2:
enum_props.upgrade_bounds(self, "bounds")
self.version = 2
class PlasmaClickableRegionNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.types.Node):
class PlasmaClickableRegionNode(idprops.IDPropObjectMixin, PlasmaVersionedNode, bpy.types.Node):
bl_category = "CONDITIONS"
bl_idname = "PlasmaClickableRegionNode"
bl_label = "Clickable Region Settings"
@ -166,9 +179,9 @@ class PlasmaClickableRegionNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.t
type=bpy.types.Object,
poll=idprops.poll_mesh_objects)
bounds = enum_props.bounds(
"region_object", store_on_collider=False,
"region_object",
name="Bounds",
description="Physical object's bounds (NOTE: only used if your clickable is not a collider)",
description="Physical object's bounds",
default="hull"
)
@ -220,6 +233,18 @@ class PlasmaClickableRegionNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.t
def _idprop_mapping(cls):
return {"region_object": "region"}
@property
def latest_version(self):
return 2
def upgrade(self):
# In version 1 of this node, the bounds type was stored on this node. This could
# be overridden by whatever was in the collision modifier. Version 2 changes the
# bounds property to proxy to the collision modifier's bounds settings.
if self.version == 1:
enum_props.upgrade_bounds(self, "bounds")
self.version = 2
class PlasmaClickableRegionSocket(PlasmaNodeSocketBase, bpy.types.NodeSocket):
bl_color = (0.412, 0.0, 0.055, 1.0)
@ -400,7 +425,7 @@ class PlasmaVolumeReportNode(PlasmaNodeBase, bpy.types.Node):
row.prop(self, "threshold", text="")
class PlasmaVolumeSensorNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.types.Node):
class PlasmaVolumeSensorNode(idprops.IDPropObjectMixin, PlasmaVersionedNode, bpy.types.Node):
bl_category = "CONDITIONS"
bl_idname = "PlasmaVolumeSensorNode"
bl_label = "Region Sensor"
@ -425,7 +450,7 @@ class PlasmaVolumeSensorNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.type
type=bpy.types.Object,
poll=idprops.poll_mesh_objects)
bounds = enum_props.bounds(
"region_object", store_on_collider=False,
"region_object",
name="Bounds",
description="Physical object's bounds"
)
@ -593,6 +618,18 @@ class PlasmaVolumeSensorNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.type
return (self.find_input_socket("exit").allow or
self.find_input("exit", "PlasmaVolumeReportNode") is not None)
@property
def latest_version(self):
return 2
def upgrade(self):
# In version 1 of this node, the bounds type was stored on this node. This could
# be overridden by whatever was in the collision modifier. Version 2 changes the
# bounds property to proxy to the collision modifier's bounds settings.
if self.version == 1:
enum_props.upgrade_bounds(self, "bounds")
self.version = 2
class PlasmaVolumeSettingsSocket(PlasmaNodeSocketBase):
bl_color = (43.1, 24.7, 0.0, 1.0)

4
korman/properties/modifiers/base.py

@ -263,7 +263,7 @@ def _restore_properties(dummy):
# again and BOOM--there are no deprecated properties available. Therefore,
# we reregister them here.
for mod_cls in PlasmaModifierUpgradable.__subclasses__():
for prop_name in mod_cls.deprecated_properties:
for prop_name in getattr(mod_cls, "deprecated_properties", []):
# Unregistered propertes are a sequence of (property function,
# property keyword arguments). Interesting design decision :)
prop_cb, prop_kwargs = getattr(mod_cls, prop_name)
@ -283,6 +283,6 @@ def _upgrade_modifiers(dummy):
# Now that everything is upgraded, forcibly remove all properties
# from the modifiers to prevent sneaky zombie-data type export bugs
for mod_cls in PlasmaModifierUpgradable.__subclasses__():
for prop in mod_cls.deprecated_properties:
for prop in getattr(mod_cls, "deprecated_properties", []):
RemoveProperty(mod_cls, attr=prop)
bpy.app.handlers.load_post.append(_upgrade_modifiers)

15
korman/properties/modifiers/region.py

@ -22,7 +22,7 @@ from ...exporter import ExportError, ExportAssertionError
from ...helpers import bmesh_from_object
from ... import idprops
from .base import PlasmaModifierProperties, PlasmaModifierLogicWiz
from .base import PlasmaModifierProperties, PlasmaModifierUpgradable, PlasmaModifierLogicWiz
from ... import enum_props
from ..prop_camera import PlasmaCameraProperties
@ -128,7 +128,7 @@ class PlasmaCameraRegion(PlasmaModifierProperties):
return self.camera_type == "auto_follow"
class PlasmaFootstepRegion(PlasmaModifierProperties, PlasmaModifierLogicWiz):
class PlasmaFootstepRegion(PlasmaModifierProperties, PlasmaModifierUpgradable, PlasmaModifierLogicWiz):
pl_id = "footstep"
bl_category = "Region"
@ -143,7 +143,6 @@ class PlasmaFootstepRegion(PlasmaModifierProperties, PlasmaModifierLogicWiz):
default="stone"
)
bounds = enum_props.bounds(
store_on_collider=False,
name="Region Bounds",
description="Physical object's bounds",
default="hull"
@ -176,6 +175,16 @@ class PlasmaFootstepRegion(PlasmaModifierProperties, PlasmaModifierLogicWiz):
def key_name(self):
return "{}_FootRgn".format(self.id_data.name)
@property
def latest_version(self):
return 2
def upgrade(self):
# Version 2 converts the bounds type to a proxy to the collision modifier.
if self.current_version < 2:
enum_props.upgrade_bounds(self, "bounds")
self.current_version = 2
class PlasmaPanicLinkRegion(PlasmaModifierProperties):
pl_id = "paniclink"

Loading…
Cancel
Save