Browse Source

Add entry cameras to the Spawn Point Modifier.

This is a 1:1 implementation of how entry cameras are implemented in
Doobes' Ages. The problem with this is that it assumes there is a single
link-in point that we will always link into.
pull/395/head
Adam Johnson 11 months ago
parent
commit
9363757d36
Signed by: Hoikas
GPG Key ID: 0B6515D6FF6F271E
  1. 15
      korman/exporter/utils.py
  2. 98
      korman/properties/modifiers/logic.py
  3. 19
      korman/ui/modifiers/logic.py

15
korman/exporter/utils.py

@ -20,6 +20,7 @@ import bpy
import mathutils import mathutils
from contextlib import contextmanager from contextlib import contextmanager
import enum
from typing import * from typing import *
from PyHSPlasma import * from PyHSPlasma import *
@ -122,7 +123,12 @@ def create_camera_object(name: str) -> bpy.types.Object:
bpy.context.scene.objects.link(cam_obj) bpy.context.scene.objects.link(cam_obj)
return cam_obj return cam_obj
def create_cube_region(name: str, size: float, owner_object: bpy.types.Object) -> bpy.types.Object: class CubeRegionOrigin(enum.Enum):
center = enum.auto()
bottom = enum.auto()
def create_cube_region(name: str, size: float, owner_object: bpy.types.Object, origin: CubeRegionOrigin = CubeRegionOrigin.center) -> bpy.types.Object:
"""Create a cube shaped region object""" """Create a cube shaped region object"""
region_object = BMeshObject(name) region_object = BMeshObject(name)
region_object.plasma_object.enabled = True region_object.plasma_object.enabled = True
@ -130,11 +136,12 @@ def create_cube_region(name: str, size: float, owner_object: bpy.types.Object) -
region_object.hide_render = True region_object.hide_render = True
with region_object as bm: with region_object as bm:
bmesh.ops.create_cube(bm, size=(size)) bmesh.ops.create_cube(bm, size=(size))
origin = owner_object.matrix_world.translation - region_object.matrix_world.translation
if origin == CubeRegionOrigin.bottom:
origin.z += size * 0.5
bmesh.ops.transform( bmesh.ops.transform(
bm, bm,
matrix=mathutils.Matrix.Translation( matrix=mathutils.Matrix.Translation(origin),
owner_object.matrix_world.translation - region_object.matrix_world.translation
),
space=region_object.matrix_world, verts=bm.verts space=region_object.matrix_world, verts=bm.verts
) )
return region_object.release() return region_object.release()

98
korman/properties/modifiers/logic.py

@ -13,16 +13,26 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Korman. If not, see <http://www.gnu.org/licenses/>. # along with Korman. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bmesh import bmesh
import bpy import bpy
from bpy.props import * from bpy.props import *
import mathutils import mathutils
from PyHSPlasma import * from PyHSPlasma import *
from typing import *
if TYPE_CHECKING:
from ...exporter import Exporter
from ...nodes.node_conditions import *
from ...nodes.node_messages import *
from ...nodes.node_responder import *
from ...addon_prefs import game_versions from ...addon_prefs import game_versions
from .base import PlasmaModifierProperties, PlasmaModifierLogicWiz from .base import PlasmaModifierProperties, PlasmaModifierLogicWiz
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
class PlasmaVersionedNodeTree(idprops.IDPropMixin, bpy.types.PropertyGroup): class PlasmaVersionedNodeTree(idprops.IDPropMixin, bpy.types.PropertyGroup):
version = EnumProperty(name="Version", version = EnumProperty(name="Version",
@ -76,7 +86,7 @@ class PlasmaAdvancedLogic(PlasmaModifierProperties):
return any((i.node_tree.requires_actor for i in self.logic_groups if i.node_tree)) return any((i.node_tree.requires_actor for i in self.logic_groups if i.node_tree))
class PlasmaSpawnPoint(PlasmaModifierProperties): class PlasmaSpawnPoint(PlasmaModifierProperties, PlasmaModifierLogicWiz):
pl_id = "spawnpoint" pl_id = "spawnpoint"
bl_category = "Logic" bl_category = "Logic"
@ -84,10 +94,90 @@ class PlasmaSpawnPoint(PlasmaModifierProperties):
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(
name="Entry Camera",
description="Camera to use when the player spawns at this location",
type=bpy.types.Object,
poll=idprops.poll_camera_objects
)
exit_region = PointerProperty(
name="Exit Region",
description="Pop the camera when the player exits this region",
type=bpy.types.Object,
poll=idprops.poll_mesh_objects
)
bounds_type = EnumProperty(
name="Bounds",
description="",
items=bounds_types,
get=_get_bounds,
set=_set_bounds,
default="hull"
)
def pre_export(self, exporter: Exporter, bo: bpy.types.Object) -> None:
if self.entry_camera is None:
return
if self.exit_region is None:
self.exit_region = yield utils.create_cube_region(
f"{self.key_name}_ExitRgn", 6.0,
bo, utils.CubeRegionOrigin.bottom
)
yield self.convert_logic(bo)
def logicwiz(self, bo, tree):
nodes = tree.nodes
# Generate two responders. The first responder will push the entry camera
# onto the camera stack when we first enter the region - usually on link in.
# Then, disable the entry sensor once it's fired. The second responder will
# always pop the entry camera
self._create_nodes(nodes, enter=True, exit=False, camCmd="push", enable="disable")
self._create_nodes(nodes, enter=False, exit=True, camCmd="pop")
def _create_nodes(self, nodes, *, enter: Optional[bool] = None, camCmd: Optional[str] = None, enable: Optional[str] = None):
volume_sensor: PlasmaVolumeSensorNode = nodes.new("PlasmaVolumeSensorNode")
volume_sensor.bounds = self.bounds_type
if enter is not None:
volume_sensor.find_input_socket("enter").allow = enter
if exit is not None:
volume_sensor.find_input_socket("exit").allow = exit
responder: PlasmaResponderNode = nodes.new("PlasmaResponderNode")
responder.link_input(volume_sensor, "satisfies", "condition")
responder_state: PlasmaResponderStateNode = nodes.new("PlasmaResponderStateNode")
responder_state.link_input(responder, "state_refs", "resp")
camera_msg: PlasmaCameraMsgNode = nodes.new("PlasmaCameraMsgNode")
assert camCmd in {"push", "pop"}
camera_msg.cmd = camCmd
camera_msg.camera = self.entry_camera
camera_msg.link_input(responder_state, "msgs", "sender")
if enable is not None:
enable_msg: PlasmaEnableMsgNode = nodes.new("PlasmaEnableMsgNode")
enable_LUT = {"enable": "kEnable", "disable": "kDisable"}
enable_msg.cmd = enable_LUT[enable]
enable_msg.settings = {"kModifiers"}
enable_msg.link_input(responder_state, "msgs", "sender")
enable_msg.link_output(volume_sensor, "receivers", "message")
def export(self, exporter, bo, so): def export(self, exporter, bo, so):
# Not much to this modifier... It's basically a flag that tells the engine, "hey, this is a exporter.mgr.add_object(pl=plSpawnModifier, so=so, name=self.key_name)
# place the avatar can show up." Nice to have a simple one to get started with.
spawn = exporter.mgr.add_object(pl=plSpawnModifier, so=so, name=self.key_name)
@property @property
def requires_actor(self): def requires_actor(self):

19
korman/ui/modifiers/logic.py

@ -13,8 +13,15 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Korman. If not, see <http://www.gnu.org/licenses/>. # along with Korman. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy import bpy
from typing import *
if TYPE_CHECKING:
from ...properties.modifiers.logic import *
from .. import ui_list from .. import ui_list
class LogicListUI(bpy.types.UIList): class LogicListUI(bpy.types.UIList):
@ -36,8 +43,18 @@ def advanced_logic(modifier, layout, context):
layout.row().prop_menu_enum(logic, "version") layout.row().prop_menu_enum(logic, "version")
layout.prop(logic, "node_tree", icon="NODETREE") layout.prop(logic, "node_tree", icon="NODETREE")
def spawnpoint(modifier, layout, context): def spawnpoint(modifier: PlasmaSpawnPoint, layout, context):
layout.label(text="Avatar faces negative Y.") layout.label(text="Avatar faces negative Y.")
layout.separator()
col = layout.column()
col.prop(modifier, "entry_camera", icon="CAMERA_DATA")
sub = col.row()
sub.active = modifier.entry_camera is not None
sub.prop(modifier, "exit_region", icon="MESH_DATA")
sub = col.row()
sub.active = modifier.entry_camera is not None and modifier.exit_region is not None
sub.prop(modifier, "bounds_type")
def maintainersmarker(modifier, layout, context): def maintainersmarker(modifier, layout, context):
layout.label(text="Positive Y is North, positive Z is up.") layout.label(text="Positive Y is North, positive Z is up.")

Loading…
Cancel
Save