Compare commits

..

7 Commits

Author SHA1 Message Date
Adam Johnson b6e8c5b6dd
Update all dependencies to current. 5 months ago
Adam Johnson 9cde96a165
Re-merge pull request #395. 5 months ago
Adam Johnson c873cf968b
Don't move the original object! 10 months ago
Adam Johnson e3d3c953df
Convert to xEntryCam.py 10 months ago
Adam Johnson 5085cf5814
Add box region helper for non-cube boxes. 10 months ago
Adam Johnson e8d3cb0e5e
Fix `_create_python_attribute` for non-"simple" types. 10 months ago
Adam Johnson 9363757d36
Add entry cameras to the Spawn Point Modifier. 10 months ago
  1. 12
      cmake/Dependencies.cmake
  2. 52
      korman/exporter/utils.py
  3. 32
      korman/properties/modifiers/base.py
  4. 90
      korman/properties/modifiers/logic.py
  5. 19
      korman/ui/modifiers/logic.py

12
cmake/Dependencies.cmake

@ -189,7 +189,7 @@ endfunction()
if(korman_BUILD_JPEG) if(korman_BUILD_JPEG)
korman_add_external_project(libjpeg-turbo korman_add_external_project(libjpeg-turbo
GIT_REPOSITORY "https://github.com/libjpeg-turbo/libjpeg-turbo.git" GIT_REPOSITORY "https://github.com/libjpeg-turbo/libjpeg-turbo.git"
GIT_TAG 3.0.0 GIT_TAG 3.0.3
CMAKE_CACHE_ARGS CMAKE_CACHE_ARGS
-DBUILD_SHARED_LIBS:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=OFF
-DENABLE_SHARED:BOOL=FALSE -DENABLE_SHARED:BOOL=FALSE
@ -247,7 +247,7 @@ if(korman_BUILD_ZLIB)
endif() endif()
korman_add_external_project(zlib korman_add_external_project(zlib
GIT_REPOSITORY "https://github.com/zlib-ng/zlib-ng.git" GIT_REPOSITORY "https://github.com/zlib-ng/zlib-ng.git"
GIT_TAG 2.1.3 GIT_TAG 2.1.7
CMAKE_CACHE_ARGS CMAKE_CACHE_ARGS
-DBUILD_SHARED_LIBS:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=OFF
-DZLIB_COMPAT:BOOL=ON -DZLIB_COMPAT:BOOL=ON
@ -258,9 +258,9 @@ endif()
if(korman_BUILD_PNG) if(korman_BUILD_PNG)
korman_add_external_project(libpng korman_add_external_project(libpng
URL "https://sourceforge.net/projects/libpng/files/libpng16/1.6.40/libpng-1.6.40.tar.gz/download" URL "https://sourceforge.net/projects/libpng/files/libpng16/1.6.43/libpng-1.6.43.tar.gz/download"
DOWNLOAD_NAME "libpng-1.6.40.tar.gz" DOWNLOAD_NAME "libpng-1.6.43.tar.gz"
URL_HASH "SHA256=8f720b363aa08683c9bf2a563236f45313af2c55d542b5481ae17dd8d183bb42" URL_HASH "SHA256=e804e465d4b109b5ad285a8fb71f0dd3f74f0068f91ce3cdfde618180c174925"
CMAKE_CACHE_ARGS CMAKE_CACHE_ARGS
-DBUILD_SHARED_LIBS:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=OFF
-DPNG_EXECUTABLES:BOOL=OFF -DPNG_EXECUTABLES:BOOL=OFF
@ -273,7 +273,7 @@ if(korman_BUILD_HSPLASMA)
korman_add_external_project(HSPlasma korman_add_external_project(HSPlasma
GIT_REPOSITORY "https://github.com/H-uru/libhsplasma.git" GIT_REPOSITORY "https://github.com/H-uru/libhsplasma.git"
# Be sure to increase this as the feature set used by Korman increases # Be sure to increase this as the feature set used by Korman increases
GIT_TAG ed9c2d4c15a86e5461b52bc89a9294d82d6ab683 GIT_TAG f372a43a8ce78b056fe21c7ed372f04a88b20e98
# We can only do shallow checkouts if the above is a branch or tag. # We can only do shallow checkouts if the above is a branch or tag.
GIT_SHALLOW FALSE GIT_SHALLOW FALSE
CMAKE_CACHE_ARGS CMAKE_CACHE_ARGS

52
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 *
@ -130,21 +131,54 @@ 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 RegionOrigin(enum.Enum):
center = enum.auto()
bottom = enum.auto()
def create_cube_region(name: str, size: float, owner_object: bpy.types.Object, origin: RegionOrigin = RegionOrigin.center) -> bpy.types.Object:
"""Create a cube shaped region object""" """Create a cube shaped region object"""
# Proxy over to the generic rectangular prism implementation to
# ensure that it is well tested.
return create_box_region(name, (size, size, size), owner_object, origin)
def create_box_region(
name: str, size: Union[Tuple[float, float, float], mathutils.Vector],
owner_object: bpy.types.Object,
origin: RegionOrigin = RegionOrigin.center
) -> bpy.types.Object:
"""Create a rectangular prism region object"""
if not isinstance(size, mathutils.Vector):
size = mathutils.Vector(size)
region_object = BMeshObject(name) region_object = BMeshObject(name)
region_object.plasma_object.enabled = True region_object.plasma_object.enabled = True
region_object.plasma_object.page = owner_object.plasma_object.page region_object.plasma_object.page = owner_object.plasma_object.page
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)) center = owner_object.matrix_world.translation
bmesh.ops.transform( if origin == RegionOrigin.bottom:
bm, center = center.copy()
matrix=mathutils.Matrix.Translation( center.z += size.z * 0.5
owner_object.matrix_world.translation - region_object.matrix_world.translation vert_src = [
), (center.x + size.x * 0.5, center.y + size.y * 0.5, center.z + size.z * 0.5),
space=region_object.matrix_world, verts=bm.verts (center.x + size.x * 0.5, center.y + size.y * 0.5, center.z - size.z * 0.5),
) (center.x + size.x * 0.5, center.y - size.y * 0.5, center.z + size.z * 0.5),
(center.x + size.x * 0.5, center.y - size.y * 0.5, center.z - size.z * 0.5),
(center.x - size.x * 0.5, center.y + size.y * 0.5, center.z + size.z * 0.5),
(center.x - size.x * 0.5, center.y + size.y * 0.5, center.z - size.z * 0.5),
(center.x - size.x * 0.5, center.y - size.y * 0.5, center.z + size.z * 0.5),
(center.x - size.x * 0.5, center.y - size.y * 0.5, center.z - size.z * 0.5),
]
verts = [bm.verts.new(i) for i in vert_src]
new_face = bm.faces.new
new_face((verts[0], verts[1], verts[3], verts[2])) # X+
new_face((verts[4], verts[5], verts[7], verts[6])) # X-
new_face((verts[0], verts[1], verts[5], verts[4])) # Y+
new_face((verts[2], verts[3], verts[7], verts[6])) # Y-
new_face((verts[0], verts[2], verts[6], verts[4])) # Z+
new_face((verts[1], verts[3], verts[7], verts[5])) # Z-
return region_object.release() return region_object.release()
@contextmanager @contextmanager

32
korman/properties/modifiers/base.py

@ -13,12 +13,17 @@
# 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 bpy.props import * from bpy.props import *
import abc import abc
import itertools import itertools
from typing import Any, Dict, FrozenSet, Optional from typing import *
if TYPE_CHECKING:
from ...nodes.node_python import *
from ... import helpers from ... import helpers
@ -202,24 +207,23 @@ class PlasmaModifierLogicWiz:
pfm_node.update() pfm_node.update()
return pfm_node return pfm_node
def _create_python_attribute(self, pfm_node, attribute_name: str, attribute_type: Optional[str] = None, **kwargs): def _create_python_attribute(self, pfm_node: PlasmaPythonFileNode, attribute_name: str, **kwargs):
"""Creates and links a Python Attribute Node to the Python File Node given by `pfm_node`. """Creates and links a Python Attribute Node to the Python File Node given by `pfm_node`.
This will automatically handle simple attribute types such as numbers and strings, however, For attribute nodes that require multiple values, the `value` may be set to None and
for object linkage, you should specify the optional `attribute_type` to ensure the proper handled in your code."""
attribute type is found. For attribute nodes that require multiple values, the `value` may attribute_defn = next((i for i in pfm_node.attributes if i.attribute_name == attribute_name), None)
be set to None and handled in your code.""" if attribute_defn is None:
from ...nodes.node_python import PlasmaAttribute, PlasmaAttribNodeBase raise KeyError(attribute_name)
if attribute_type is None:
assert len(kwargs) == 1 and "value" in kwargs, \ from ...nodes.node_python import PlasmaAttribNodeBase
"In order to deduce the attribute_type, exactly one attribute value must be passed as a kw named `value`" attribute_type = attribute_defn.attribute_type
attribute_type = PlasmaAttribute.type_LUT.get(kwargs["value"].__class__)
node_cls = next((i for i in PlasmaAttribNodeBase.__subclasses__() if attribute_type in i.pl_attrib), None) node_cls = next((i for i in PlasmaAttribNodeBase.__subclasses__() if attribute_type in i.pl_attrib), None)
assert node_cls is not None, "'{}': Unable to find attribute node type for '{}' ('{}')".format( assert node_cls is not None, \
self.id_data.name, attribute_name, attribute_type f"'{self.id_data.name}': Unable to find attribute node type for '{attribute_name}' ('{attribute_type}')"
)
node = pfm_node.id_data.nodes.new(node_cls.bl_idname) node = pfm_node.id_data.nodes.new(node_cls.bl_idname)
node.link_output(pfm_node, "pfm", attribute_name) node.link_output(pfm_node, "pfm", attribute_name)
assert kwargs
for i, j in kwargs.items(): for i, j in kwargs.items():
setattr(node, i, j) setattr(node, i, j)
return node return node

90
korman/properties/modifiers/logic.py

@ -13,16 +13,35 @@
# 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
entry_cam_pfm = {
"filename": "xEntryCam.py",
"attribs": (
{ 'id': 1, 'type': "ptAttribActivator", 'name': "actRegionSensor" },
{ 'id': 2, 'type': "ptAttribSceneobject", 'name': "camera" },
{ 'id': 3, 'type': "ptAttribBoolean", 'name': "undoFirstPerson" },
)
}
class PlasmaVersionedNodeTree(idprops.IDPropMixin, bpy.types.PropertyGroup): class PlasmaVersionedNodeTree(idprops.IDPropMixin, bpy.types.PropertyGroup):
version = EnumProperty(name="Version", version = EnumProperty(name="Version",
@ -76,7 +95,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 +103,73 @@ 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_box_region(
f"{self.key_name}_ExitRgn", (2.0, 2.0, 6.0),
bo, utils.RegionOrigin.bottom
)
yield self.convert_logic(bo)
def logicwiz(self, bo, tree):
pfm_node = self._create_python_file_node(
tree,
entry_cam_pfm["filename"],
entry_cam_pfm["attribs"]
)
volume_sensor: PlasmaVolumeSensorNode = tree.nodes.new("PlasmaVolumeSensorNode")
volume_sensor.find_input_socket("enter").allow = True
volume_sensor.find_input_socket("exit").allow = True
volume_sensor.region_object = self.exit_region
volume_sensor.bounds = self.bounds_type
volume_sensor.link_output(pfm_node, "satisfies", "actRegionSensor")
self._create_python_attribute(
pfm_node,
"camera",
target_object=self.entry_camera
)
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