Browse Source

Make bounds enum properties less verbose.

Every time we need to make a place to store a region's bounds, we have
to write quite a bit of boilerplate code to stash the bounds type into
the collision modifier. This removes the need to do that by making a
helper function that generates those helper functions for us. Generally,
we would use `functools.partial` to do this, but Blender requires
function objects for the `EnumProperty`'s getter and setter. Partial
objects raise a `TypeError`.
pull/415/head
Adam Johnson 5 months ago
parent
commit
5b2c16cfb2
Signed by: Hoikas
GPG Key ID: 0B6515D6FF6F271E
  1. 62
      korman/enum_props.py
  2. 31
      korman/nodes/node_conditions.py
  3. 26
      korman/nodes/node_logic.py
  4. 17
      korman/properties/modifiers/logic.py
  5. 18
      korman/properties/modifiers/physics.py
  6. 22
      korman/properties/modifiers/region.py

62
korman/enum_props.py

@ -0,0 +1,62 @@
# This file is part of Korman.
#
# Korman is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Korman is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Korman. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
from bpy.props import *
from typing import *
# These are the kinds of physical bounds Plasma can work with.
# This sequence is acceptable in any EnumProperty
_bounds_types = (
("box", "Bounding Box", "Use a perfect bounding box"),
("sphere", "Bounding Sphere", "Use a perfect bounding sphere"),
("hull", "Convex Hull", "Use a convex set encompasing all vertices"),
("trimesh", "Triangle Mesh", "Use the exact triangle mesh (SLOW!)")
)
def _bounds_type_index(key: str) -> int:
return list(zip(*_bounds_types))[0].index(key)
def _bounds_type_str(idx: int) -> str:
return _bounds_types[idx][0]
def _get_bounds(physics_attr: Optional[str]) -> Callable[[Any], int]:
def getter(self) -> int:
physics_object = getattr(self, physics_attr) if physics_attr is not None else self.id_data
if physics_object is not None:
return _bounds_type_index(physics_object.plasma_modifiers.collision.bounds)
return _bounds_type_index("hull")
return getter
def _set_bounds(physics_attr: Optional[str]) -> Callable[[Any, int], None]:
def setter(self, value: int):
physics_object = getattr(self, physics_attr) if physics_attr is not None else self.id_data
if physics_object is not None:
physics_object.plasma_modifiers.collision.bounds = _bounds_type_str(value)
return setter
def bounds(physics_attr: Optional[str] = None, store_on_collider: bool = True, **kwargs) -> str:
assert not {"items", "get", "set"} & kwargs.keys(), "You cannot use the `items`, `get`, or `set` keyword arguments"
if store_on_collider:
kwargs["get"] = _get_bounds(physics_attr)
kwargs["set"] = _set_bounds(physics_attr)
if "default" not in kwargs:
kwargs["default"] = "hull"
return EnumProperty(
items=_bounds_types,
**kwargs
)

31
korman/nodes/node_conditions.py

@ -21,8 +21,8 @@ import math
from PyHSPlasma import * from PyHSPlasma import *
from typing import * from typing import *
from .. import enum_props
from .node_core import * from .node_core import *
from ..properties.modifiers.physics import bounds_types
from .. import idprops from .. import idprops
class PlasmaClickableNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.types.Node): class PlasmaClickableNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.types.Node):
@ -38,10 +38,13 @@ class PlasmaClickableNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.types.N
description="Mesh object that is clickable", description="Mesh object that is clickable",
type=bpy.types.Object, type=bpy.types.Object,
poll=idprops.poll_mesh_objects) poll=idprops.poll_mesh_objects)
bounds = EnumProperty(name="Bounds",
description="Clickable's bounds (NOTE: only used if your clickable is not a collider)", bounds = enum_props.bounds(
items=bounds_types, "clickable_object", store_on_collider=False,
default="hull") name="Bounds",
description="Clickable's bounds (NOTE: only used if your clickable is not a collider)",
default="hull"
)
input_sockets: dict[str, Any] = { input_sockets: dict[str, Any] = {
"region": { "region": {
@ -162,10 +165,12 @@ class PlasmaClickableRegionNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.t
description="Object that defines the region mesh", description="Object that defines the region mesh",
type=bpy.types.Object, type=bpy.types.Object,
poll=idprops.poll_mesh_objects) poll=idprops.poll_mesh_objects)
bounds = EnumProperty(name="Bounds", bounds = enum_props.bounds(
description="Physical object's bounds (NOTE: only used if your clickable is not a collider)", "region_object", store_on_collider=False,
items=bounds_types, name="Bounds",
default="hull") description="Physical object's bounds (NOTE: only used if your clickable is not a collider)",
default="hull"
)
output_sockets = { output_sockets = {
"satisfies": { "satisfies": {
@ -419,9 +424,11 @@ class PlasmaVolumeSensorNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.type
description="Object that defines the region mesh", description="Object that defines the region mesh",
type=bpy.types.Object, type=bpy.types.Object,
poll=idprops.poll_mesh_objects) poll=idprops.poll_mesh_objects)
bounds = EnumProperty(name="Bounds", bounds = enum_props.bounds(
description="Physical object's bounds", "region_object", store_on_collider=False,
items=bounds_types) name="Bounds",
description="Physical object's bounds"
)
# Detector Properties # Detector Properties
report_on = EnumProperty(name="Triggerers", report_on = EnumProperty(name="Triggerers",

26
korman/nodes/node_logic.py

@ -20,8 +20,8 @@ from bpy.props import *
from typing import * from typing import *
from PyHSPlasma import * from PyHSPlasma import *
from .. import enum_props
from .node_core import * from .node_core import *
from ..properties.modifiers.physics import bounds_types, bounds_type_index, bounds_type_str
from .. import idprops from .. import idprops
class PlasmaExcludeRegionNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.types.Node): class PlasmaExcludeRegionNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.types.Node):
@ -33,25 +33,19 @@ class PlasmaExcludeRegionNode(idprops.IDPropObjectMixin, PlasmaNodeBase, bpy.typ
# ohey, this can be a Python attribute # ohey, this can be a Python attribute
pl_attrib = {"ptAttribExcludeRegion"} pl_attrib = {"ptAttribExcludeRegion"}
def _get_bounds(self):
if self.region_object is not None:
return bounds_type_index(self.region_object.plasma_modifiers.collision.bounds)
return bounds_type_index("hull")
def _set_bounds(self, value):
if self.region_object is not None:
self.region_object.plasma_modifiers.collision.bounds = bounds_type_str(value)
region_object = PointerProperty(name="Region", region_object = PointerProperty(name="Region",
description="Region object's name", description="Region object's name",
type=bpy.types.Object, type=bpy.types.Object,
poll=idprops.poll_mesh_objects) poll=idprops.poll_mesh_objects)
bounds = EnumProperty(name="Bounds", bounds = enum_props.bounds(
description="Region bounds", "region_object",
items=bounds_types, name="Bounds",
get=_get_bounds, description="Region bounds"
set=_set_bounds) )
block_cameras = BoolProperty(name="Block Cameras", block_cameras = BoolProperty(
description="The region blocks cameras when it has been cleared") name="Block Cameras",
description="The region blocks cameras when it has been cleared"
)
input_sockets:dict[str, dict[str, Any]] = { input_sockets:dict[str, dict[str, Any]] = {
"safe_point": { "safe_point": {

17
korman/properties/modifiers/logic.py

@ -30,9 +30,9 @@ if TYPE_CHECKING:
from ...addon_prefs import game_versions from ...addon_prefs import game_versions
from .base import PlasmaModifierProperties, PlasmaModifierLogicWiz from .base import PlasmaModifierProperties, PlasmaModifierLogicWiz
from ... import enum_props
from ...exporter import ExportError, utils from ...exporter import ExportError, utils
from ... import idprops from ... import idprops
from .physics import bounds_type_index, bounds_type_str, bounds_types
entry_cam_pfm = { entry_cam_pfm = {
"filename": "xEntryCam.py", "filename": "xEntryCam.py",
@ -103,15 +103,6 @@ class PlasmaSpawnPoint(PlasmaModifierProperties, PlasmaModifierLogicWiz):
bl_description = "Point at which avatars link into the Age" bl_description = "Point at which avatars link into the Age"
bl_object_types = {"EMPTY"} bl_object_types = {"EMPTY"}
def _get_bounds(self) -> int:
if self.exit_region is not None:
return bounds_type_index(self.exit_region.plasma_modifiers.collision.bounds_type)
return bounds_type_index("hull")
def _set_bounds(self, value: int) -> None:
if self.exit_region is not None:
self.exit_region.plasma_modifiers.collision.bounds_type = bounds_type_str(value)
entry_camera = PointerProperty( entry_camera = PointerProperty(
name="Entry Camera", name="Entry Camera",
description="Camera to use when the player spawns at this location", description="Camera to use when the player spawns at this location",
@ -126,12 +117,10 @@ class PlasmaSpawnPoint(PlasmaModifierProperties, PlasmaModifierLogicWiz):
poll=idprops.poll_mesh_objects poll=idprops.poll_mesh_objects
) )
bounds_type = EnumProperty( bounds_type = enum_props.bounds(
"exit_region",
name="Bounds", name="Bounds",
description="", description="",
items=bounds_types,
get=_get_bounds,
set=_set_bounds,
default="hull" default="hull"
) )

18
korman/properties/modifiers/physics.py

@ -18,18 +18,10 @@ from bpy.props import *
from PyHSPlasma import * from PyHSPlasma import *
from .base import PlasmaModifierProperties from .base import PlasmaModifierProperties
from ...enum_props import _bounds_types
from ...exporter import ExportError from ...exporter import ExportError
from ... import idprops from ... import idprops
# These are the kinds of physical bounds Plasma can work with.
# This sequence is acceptable in any EnumProperty
bounds_types = (
("box", "Bounding Box", "Use a perfect bounding box"),
("sphere", "Bounding Sphere", "Use a perfect bounding sphere"),
("hull", "Convex Hull", "Use a convex set encompasing all vertices"),
("trimesh", "Triangle Mesh", "Use the exact triangle mesh (SLOW!)")
)
# These are the collision sound surface types # These are the collision sound surface types
surface_types = ( surface_types = (
# Danger: do not reorder this one. # Danger: do not reorder this one.
@ -55,12 +47,6 @@ subworld_types = (
("subworld", "Separate World", "Causes all objects to be placed in a separate physics simulation"), ("subworld", "Separate World", "Causes all objects to be placed in a separate physics simulation"),
) )
def bounds_type_index(key):
return list(zip(*bounds_types))[0].index(key)
def bounds_type_str(idx):
return bounds_types[idx][0]
def _set_phys_prop(prop, sim, phys, value=True): def _set_phys_prop(prop, sim, phys, value=True):
"""Sets properties on plGenericPhysical and plSimulationInterface (seeing as how they are duped)""" """Sets properties on plGenericPhysical and plSimulationInterface (seeing as how they are duped)"""
sim.setProperty(prop, value) sim.setProperty(prop, value)
@ -78,7 +64,7 @@ class PlasmaCollider(PlasmaModifierProperties):
bounds = EnumProperty(name="Bounds Type", bounds = EnumProperty(name="Bounds Type",
description="", description="",
items=bounds_types, items=_bounds_types,
default="hull") default="hull")
avatar_blocker = BoolProperty(name="Blocks Avatars", avatar_blocker = BoolProperty(name="Blocks Avatars",

22
korman/properties/modifiers/region.py

@ -23,8 +23,8 @@ from ...helpers import bmesh_from_object
from ... import idprops from ... import idprops
from .base import PlasmaModifierProperties, PlasmaModifierLogicWiz from .base import PlasmaModifierProperties, PlasmaModifierLogicWiz
from ... import enum_props
from ..prop_camera import PlasmaCameraProperties from ..prop_camera import PlasmaCameraProperties
from .physics import bounds_types
footstep_surface_ids = { footstep_surface_ids = {
"dirt": 0, "dirt": 0,
@ -136,14 +136,18 @@ class PlasmaFootstepRegion(PlasmaModifierProperties, PlasmaModifierLogicWiz):
bl_description = "Footstep Region" bl_description = "Footstep Region"
bl_object_types = {"MESH"} bl_object_types = {"MESH"}
surface = EnumProperty(name="Surface", surface = EnumProperty(
description="What kind of surface are we walking on?", name="Surface",
items=footstep_surfaces, description="What kind of surface are we walking on?",
default="stone") items=footstep_surfaces,
bounds = EnumProperty(name="Region Bounds", default="stone"
description="Physical object's bounds", )
items=bounds_types, bounds = enum_props.bounds(
default="hull") store_on_collider=False,
name="Region Bounds",
description="Physical object's bounds",
default="hull"
)
def logicwiz(self, bo, tree): def logicwiz(self, bo, tree):
nodes = tree.nodes nodes = tree.nodes

Loading…
Cancel
Save