|
|
@ -13,12 +13,16 @@ |
|
|
|
# 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 * |
|
|
|
|
|
|
|
|
|
|
|
from collections.abc import Iterable |
|
|
|
from collections.abc import Iterable |
|
|
|
from contextlib import contextmanager |
|
|
|
from contextlib import contextmanager |
|
|
|
from pathlib import Path |
|
|
|
from pathlib import Path |
|
|
|
|
|
|
|
from typing import * |
|
|
|
|
|
|
|
|
|
|
|
from PyHSPlasma import * |
|
|
|
from PyHSPlasma import * |
|
|
|
|
|
|
|
|
|
|
|
from .. import enum_props |
|
|
|
from .. import enum_props |
|
|
@ -68,9 +72,12 @@ _attrib2param = { |
|
|
|
_attrib_key_types = { |
|
|
|
_attrib_key_types = { |
|
|
|
"ptAttribSceneobject": plFactory.ClassIndex("plSceneObject"), |
|
|
|
"ptAttribSceneobject": plFactory.ClassIndex("plSceneObject"), |
|
|
|
"ptAttribSceneobjectList": plFactory.ClassIndex("plSceneObject"), |
|
|
|
"ptAttribSceneobjectList": plFactory.ClassIndex("plSceneObject"), |
|
|
|
"ptAttribActivator": plFactory.ClassIndex("plLogicModifier"), |
|
|
|
"ptAttribActivator": (plFactory.ClassIndex("plLogicModifier"), |
|
|
|
"ptAttribActivatorList": plFactory.ClassIndex("plLogicModifier"), |
|
|
|
plFactory.ClassIndex("plPythonFileMod")), |
|
|
|
"ptAttribNamedActivator": plFactory.ClassIndex("plLogicModifier"), |
|
|
|
"ptAttribActivatorList": (plFactory.ClassIndex("plLogicModifier"), |
|
|
|
|
|
|
|
plFactory.ClassIndex("plPythonFileMod")), |
|
|
|
|
|
|
|
"ptAttribNamedActivator": (plFactory.ClassIndex("plLogicModifier"), |
|
|
|
|
|
|
|
plFactory.ClassIndex("plPythonFileMod")), |
|
|
|
"ptAttribResponder": plFactory.ClassIndex("plResponderModifier"), |
|
|
|
"ptAttribResponder": plFactory.ClassIndex("plResponderModifier"), |
|
|
|
"ptAttribResponderList": plFactory.ClassIndex("plResponderModifier"), |
|
|
|
"ptAttribResponderList": plFactory.ClassIndex("plResponderModifier"), |
|
|
|
"ptAttribNamedResponder": plFactory.ClassIndex("plResponderModifier"), |
|
|
|
"ptAttribNamedResponder": plFactory.ClassIndex("plResponderModifier"), |
|
|
@ -187,6 +194,17 @@ class PlasmaPythonFileNode(PlasmaVersionedNode, bpy.types.Node): |
|
|
|
bl_label = "Python File" |
|
|
|
bl_label = "Python File" |
|
|
|
bl_width_default = 290 |
|
|
|
bl_width_default = 290 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Yas, a PythonFileMod can activate another PythonFileMod |
|
|
|
|
|
|
|
pl_attrib = {"ptAttribActivator", "ptAttribActivatorList", "ptAttribNamedActivator"} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
output_sockets: dict[str, dict[str, Any]] = { |
|
|
|
|
|
|
|
"satisfies": { |
|
|
|
|
|
|
|
"text": "Satisfies", |
|
|
|
|
|
|
|
"type": "PlasmaConditionSocket", |
|
|
|
|
|
|
|
"valid_link_nodes": "PlasmaPythonFileNode", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
def _poll_pytext(self, value): |
|
|
|
def _poll_pytext(self, value): |
|
|
|
return value.name.endswith(".py") |
|
|
|
return value.name.endswith(".py") |
|
|
|
|
|
|
|
|
|
|
@ -304,7 +322,7 @@ class PlasmaPythonFileNode(PlasmaVersionedNode, bpy.types.Node): |
|
|
|
param.value = i |
|
|
|
param.value = i |
|
|
|
|
|
|
|
|
|
|
|
if not socket.is_simple_value: |
|
|
|
if not socket.is_simple_value: |
|
|
|
self._export_key_attrib(exporter, bo, so, i, socket) |
|
|
|
self._export_key_attrib(exporter, bo, so, pfm, i, socket) |
|
|
|
pfm.addParameter(param) |
|
|
|
pfm.addParameter(param) |
|
|
|
|
|
|
|
|
|
|
|
def _export_ancillary_sceneobject(self, exporter, bo, so: plSceneObject) -> None: |
|
|
|
def _export_ancillary_sceneobject(self, exporter, bo, so: plSceneObject) -> None: |
|
|
@ -317,7 +335,7 @@ class PlasmaPythonFileNode(PlasmaVersionedNode, bpy.types.Node): |
|
|
|
exporter.report.msg(f"Marking RT light '{so.key.name}' as animated due to usage in a Python File node", so.key.name) |
|
|
|
exporter.report.msg(f"Marking RT light '{so.key.name}' as animated due to usage in a Python File node", so.key.name) |
|
|
|
light.setProperty(plLightInfo.kLPMovable, True) |
|
|
|
light.setProperty(plLightInfo.kLPMovable, True) |
|
|
|
|
|
|
|
|
|
|
|
def _export_key_attrib(self, exporter, bo, so : plSceneObject, key : plKey, socket) -> None: |
|
|
|
def _export_key_attrib(self, exporter, bo, so: plSceneObject, pfm: plPythonFileMod, key: plKey, socket) -> None: |
|
|
|
if key is None: |
|
|
|
if key is None: |
|
|
|
exporter.report.warn("Attribute '{}' didn't return a key and therefore will be unavailable to Python", |
|
|
|
exporter.report.warn("Attribute '{}' didn't return a key and therefore will be unavailable to Python", |
|
|
|
self.id_data.name, socket.links[0].name) |
|
|
|
self.id_data.name, socket.links[0].name) |
|
|
@ -333,8 +351,11 @@ class PlasmaPythonFileNode(PlasmaVersionedNode, bpy.types.Node): |
|
|
|
self.id_data.name, socket.links[0].from_node.name, |
|
|
|
self.id_data.name, socket.links[0].from_node.name, |
|
|
|
plFactory.ClassName(key.type)) |
|
|
|
plFactory.ClassName(key.type)) |
|
|
|
|
|
|
|
|
|
|
|
if isinstance(key.object, plSceneObject): |
|
|
|
key_object = key.object |
|
|
|
self._export_ancillary_sceneobject(exporter, bo, key.object) |
|
|
|
if isinstance(key_object, plSceneObject): |
|
|
|
|
|
|
|
self._export_ancillary_sceneobject(exporter, bo, key_object) |
|
|
|
|
|
|
|
elif isinstance(key_object, plPythonFileMod): |
|
|
|
|
|
|
|
key_object.addReceiver(pfm.key) |
|
|
|
|
|
|
|
|
|
|
|
def _get_attrib_sockets(self, idx): |
|
|
|
def _get_attrib_sockets(self, idx): |
|
|
|
for i in self.inputs: |
|
|
|
for i in self.inputs: |
|
|
@ -342,8 +363,9 @@ class PlasmaPythonFileNode(PlasmaVersionedNode, bpy.types.Node): |
|
|
|
yield i |
|
|
|
yield i |
|
|
|
|
|
|
|
|
|
|
|
def generate_valid_links_for(self, context, socket, is_output): |
|
|
|
def generate_valid_links_for(self, context, socket, is_output): |
|
|
|
# Python nodes have no outputs... |
|
|
|
if is_output: |
|
|
|
assert is_output is False |
|
|
|
yield from PlasmaNodeBase.generate_valid_links_for(self, context, socket, True) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
attrib_type = socket.attribute_type |
|
|
|
attrib_type = socket.attribute_type |
|
|
|
for i in bpy.types.Node.__subclasses__(): |
|
|
|
for i in bpy.types.Node.__subclasses__(): |
|
|
@ -493,6 +515,10 @@ class PlasmaPythonFileNode(PlasmaVersionedNode, bpy.types.Node): |
|
|
|
while len(unconnected) > 1: |
|
|
|
while len(unconnected) > 1: |
|
|
|
self.inputs.remove(unconnected.pop()) |
|
|
|
self.inputs.remove(unconnected.pop()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Make sure the output sockets are present and accounted for. |
|
|
|
|
|
|
|
self._update_extant_sockets(self.output_sockets, self.outputs) |
|
|
|
|
|
|
|
self._update_init_sockets(self.output_sockets, self.outputs) |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
@property |
|
|
|
def latest_version(self): |
|
|
|
def latest_version(self): |
|
|
|
return 2 |
|
|
|
return 2 |
|
|
|