mirror of https://github.com/H-uru/korman.git
Adam Johnson
10 years ago
10 changed files with 526 additions and 0 deletions
@ -0,0 +1,68 @@
|
||||
# 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/>. |
||||
|
||||
import bpy |
||||
import inspect |
||||
from nodeitems_utils import NodeCategory, NodeItem |
||||
import nodeitems_utils |
||||
|
||||
# Put all Korman node modules here... |
||||
from .node_conditions import * |
||||
from .node_core import * |
||||
from .node_logic import * |
||||
from .node_messages import * |
||||
from .node_responder import * |
||||
|
||||
class PlasmaNodeCategory(NodeCategory): |
||||
"""Plasma Node Category""" |
||||
|
||||
@classmethod |
||||
def poll(cls, context): |
||||
return (context.space_data.tree_type == "PlasmaNodeTree") |
||||
|
||||
# Here's what you need to know about this... |
||||
# If you add a new category, put the pretty name here! |
||||
# If you're making a new Node, ensure that your bl_idname attribute is present AND matches |
||||
# the class name. Otherwise, absolutely fascinating things will happen. Don't expect for me |
||||
# to come and rescue you from it, either. |
||||
_kategory_names = { |
||||
"CONDITIONS": "Conditions", |
||||
"LOGIC": "Logic", |
||||
"MSG": "Message", |
||||
} |
||||
|
||||
# Now, generate the categories as best we can... |
||||
_kategories = {} |
||||
for cls in dict(globals()).values(): |
||||
if inspect.isclass(cls): |
||||
if not issubclass(cls, PlasmaNodeBase) or not issubclass(cls, bpy.types.Node): |
||||
continue |
||||
else: |
||||
continue |
||||
try: |
||||
_kategories[cls.bl_category].append(cls) |
||||
except LookupError: |
||||
_kategories[cls.bl_category] = [cls,] |
||||
_actual_kategories = [] |
||||
for i in sorted(_kategories.keys(), key=lambda x: _kategory_names[x]): |
||||
# Note that even though we're sorting the category names, Blender appears to not care... |
||||
_kat_items = [NodeItem(j.bl_idname) for j in sorted(_kategories[i], key=lambda x: x.bl_label)] |
||||
_actual_kategories.append(PlasmaNodeCategory(i, _kategory_names[i], items=_kat_items)) |
||||
|
||||
def register(): |
||||
nodeitems_utils.register_node_categories("PLASMA_NODES", _actual_kategories) |
||||
|
||||
def unregister(): |
||||
nodeitems_utils.unregister_node_categories("PLASMA_NODES") |
@ -0,0 +1,98 @@
|
||||
# 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/>. |
||||
|
||||
import bpy |
||||
from bpy.props import * |
||||
|
||||
from .node_core import PlasmaNodeBase, PlasmaNodeSocketBase |
||||
from ..properties.modifiers.physics import bounds_types |
||||
|
||||
class PlasmaConditionSocket(PlasmaNodeSocketBase, bpy.types.NodeSocket): |
||||
bl_color = (0.188, 0.086, 0.349, 1.0) |
||||
|
||||
|
||||
class PlasmaVolumeReportNode(PlasmaNodeBase, bpy.types.Node): |
||||
bl_category = "CONDITIONS" |
||||
bl_idname = "PlasmaVoumeReportNode" |
||||
bl_label = "Region Trigger Settings" |
||||
|
||||
report_when = EnumProperty(name="When", |
||||
description="When the region should trigger", |
||||
items=[("each", "Each Event", "The region will trigger on every enter/exit"), |
||||
("count", "Population", "When the region has a certain number of objects inside it")]) |
||||
threshold = IntProperty(name="Threshold", |
||||
description="How many objects should be in the region for it to trigger", |
||||
min=1) |
||||
|
||||
def init(self, context): |
||||
self.outputs.new("PlasmaVolumeSettingsSocketOut", "Trigger Settings") |
||||
|
||||
def draw_buttons(self, context, layout): |
||||
layout.prop(self, "report_when") |
||||
if self.report_when == "count": |
||||
row = layout.row() |
||||
row.label("Threshold: ") |
||||
row.prop(self, "threshold", text="") |
||||
|
||||
|
||||
class PlasmaVolumeSensorNode(PlasmaNodeBase, bpy.types.Node): |
||||
bl_category = "CONDITIONS" |
||||
bl_idname = "PlasmaVolumeSensorNode" |
||||
bl_label = "Region Sensor" |
||||
bl_width_default = 190 |
||||
|
||||
# Region Mesh |
||||
region = StringProperty(name="Region", |
||||
description="Object that defines the region mesh") |
||||
bounds = EnumProperty(name="Bounds", |
||||
description="Physical object's bounds", |
||||
items=bounds_types) |
||||
|
||||
# Detector Properties |
||||
report_on = EnumProperty(name="Triggerers", |
||||
description="What triggers this region?", |
||||
options={"ANIMATABLE", "ENUM_FLAG"}, |
||||
items=[("avatar", "Avatars", "Avatars trigger this region"), |
||||
("dynamics", "Dynamics", "Any non-avatar dynamic physical object (eg kickables)")], |
||||
default={"avatar"}) |
||||
|
||||
def init(self, context): |
||||
self.inputs.new("PlasmaVolumeSettingsSocketIn", "Trigger on Enter", "enter") |
||||
self.inputs.new("PlasmaVolumeSettingsSocketIn", "Trigger on Exit", "exit") |
||||
self.outputs.new("PlasmaConditionSocket", "Satisfies", "satisfies") |
||||
|
||||
def draw_buttons(self, context, layout): |
||||
layout.prop(self, "report_on") |
||||
|
||||
# Okay, if they changed the name of the ObData, that's THEIR problem... |
||||
layout.prop_search(self, "region", bpy.data, "meshes", icon="MESH_DATA") |
||||
layout.prop(self, "bounds") |
||||
|
||||
|
||||
class PlasmaVolumeSettingsSocket(PlasmaNodeSocketBase): |
||||
bl_color = (43.1, 24.7, 0.0, 1.0) |
||||
|
||||
|
||||
class PlasmaVolumeSettingsSocketIn(PlasmaVolumeSettingsSocket, bpy.types.NodeSocket): |
||||
allow = BoolProperty() |
||||
|
||||
def draw(self, context, layout, node, text): |
||||
if not self.is_linked: |
||||
layout.prop(self, "allow", text="") |
||||
layout.label(text) |
||||
|
||||
|
||||
class PlasmaVolumeSettingsSocketOut(PlasmaVolumeSettingsSocket, bpy.types.NodeSocket): |
||||
pass |
@ -0,0 +1,87 @@
|
||||
# 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/>. |
||||
|
||||
import bpy |
||||
|
||||
class PlasmaNodeBase: |
||||
def find_input(self, key, idname=None): |
||||
for i in self.inputs: |
||||
if i.identifier == key: |
||||
if i.links: |
||||
node = i.links[0].from_node |
||||
if idname is not None and idname != node.bl_idname: |
||||
return None |
||||
return node |
||||
else: |
||||
return None |
||||
raise KeyError(key) |
||||
|
||||
def find_input_socket(self, key): |
||||
for i in self.inputs: |
||||
if i.identifier == key: |
||||
return i |
||||
raise KeyError(key) |
||||
|
||||
def find_outputs(self, key, idname=None): |
||||
for i in self.outputs: |
||||
if i.identifier == key: |
||||
for j in i.links: |
||||
node = j.to_node |
||||
if idname is not None and idname != node.bl_idname: |
||||
continue |
||||
yield node |
||||
|
||||
def find_output_socket(self, key): |
||||
for i in self.outputs: |
||||
if i.identifier == key: |
||||
return i |
||||
raise KeyError(key) |
||||
|
||||
def link_input(self, tree, node, out_key, in_key): |
||||
"""Links a given Node's output socket to a given input socket on this Node""" |
||||
in_socket = self.find_input_socket(in_key) |
||||
out_socket = node.find_output_socket(out_key) |
||||
link = tree.links.new(in_socket, out_socket) |
||||
|
||||
def link_output(self, tree, node, out_key, in_key): |
||||
"""Links a given Node's input socket to a given output socket on this Node""" |
||||
in_socket = node.find_input_socket(in_key) |
||||
out_socket = self.find_output_socket(out_key) |
||||
link = tree.links.new(in_socket, out_socket) |
||||
|
||||
@classmethod |
||||
def poll(cls, context): |
||||
return (context.bl_idname == "PlasmaNodeTree") |
||||
|
||||
|
||||
class PlasmaNodeSocketBase: |
||||
def draw(self, context, layout, node, text): |
||||
layout.label(text) |
||||
|
||||
def draw_color(self, context, node): |
||||
# It's so tempting to just do RGB sometimes... Let's be nice. |
||||
if len(self.bl_color) == 3: |
||||
return tuple(self.bl_color[0], self.bl_color[1], self.bl_color[2], 1.0) |
||||
return self.bl_color |
||||
|
||||
|
||||
class PlasmaNodeTree(bpy.types.NodeTree): |
||||
bl_idname = "PlasmaNodeTree" |
||||
bl_label = "Plasma" |
||||
bl_icon = "NODETREE" |
||||
|
||||
@classmethod |
||||
def poll(cls, context): |
||||
return (context.scene.render.engine == "PLASMA_GAME") |
@ -0,0 +1,31 @@
|
||||
# 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/>. |
||||
|
||||
import bpy |
||||
|
||||
from .node_core import * |
||||
|
||||
class PlasmaLogicTriggerNode(PlasmaNodeBase, bpy.types.Node): |
||||
bl_category = "LOGIC" |
||||
bl_idname = "PlasmaLogicTriggerNode" |
||||
bl_label = "Logic Trigger" |
||||
|
||||
def init(self, context): |
||||
self.inputs.new("PlasmaConditionSocket", "Condition", "condition") |
||||
self.outputs.new("PlasmaRespTriggerSocket", "Trigger", "trigger") |
||||
|
||||
|
||||
class PlasmaRespTriggerSocket(PlasmaNodeSocketBase, bpy.types.NodeSocket): |
||||
bl_color = (0.384, 0.239, 0.239, 1.0) |
@ -0,0 +1,40 @@
|
||||
# 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/>. |
||||
|
||||
import bpy |
||||
from bpy.props import * |
||||
|
||||
from .node_core import * |
||||
from ..properties.modifiers.region import footstep_surfaces, footstep_surface_ids |
||||
|
||||
class PlasmaMessageSocket(PlasmaNodeSocketBase, bpy.types.NodeSocket): |
||||
bl_color = (0.004, 0.282, 0.349, 1.0) |
||||
|
||||
|
||||
class PlasmaFootstepSoundMsgNode(PlasmaNodeBase, bpy.types.Node): |
||||
bl_category = "MSG" |
||||
bl_idname = "PlasmaFootstepSoundMsgNode" |
||||
bl_label = "Footstep Sound" |
||||
|
||||
surface = EnumProperty(name="Surface", |
||||
description="What kind of surface are we walking on?", |
||||
items=footstep_surfaces, |
||||
default="stone") |
||||
|
||||
def init(self, context): |
||||
self.inputs.new("PlasmaMessageSocket", "Sender", "sender") |
||||
|
||||
def draw_buttons(self, context, layout): |
||||
layout.prop(self, "surface") |
@ -0,0 +1,108 @@
|
||||
# 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/>. |
||||
|
||||
import bpy |
||||
from bpy.props import * |
||||
import uuid |
||||
|
||||
from .node_core import * |
||||
|
||||
class PlasmaResponderNode(PlasmaNodeBase, bpy.types.Node): |
||||
bl_category = "LOGIC" |
||||
bl_idname = "PlasmaResponderNode" |
||||
bl_label = "Responder" |
||||
|
||||
def init(self, context): |
||||
self.inputs.new("PlasmaRespTriggerSocket", "Trigger", "whodoneit") |
||||
self.outputs.new("PlasmaRespStateSocket", "States", "states") |
||||
|
||||
|
||||
class PlasmaResponderStateNode(PlasmaNodeBase, bpy.types.Node): |
||||
bl_category = "LOGIC" |
||||
bl_idname = "PlasmaResponderStateNode" |
||||
bl_label = "Responder State" |
||||
|
||||
def init(self, context): |
||||
self.inputs.new("PlasmaRespStateSocket", "Condition", "whodoneit") |
||||
self.outputs.new("PlasmaRespCommandSocket", "Commands", "cmds") |
||||
self.outputs.new("PlasmaRespStateSocket", "Trigger", "gotostate").link_limit = 1 |
||||
|
||||
|
||||
class PlasmaRespStateSocketBase(PlasmaNodeSocketBase): |
||||
bl_color = (0.388, 0.78, 0.388, 1.0) |
||||
|
||||
|
||||
class PlasmaRespStateSocket(PlasmaRespStateSocketBase, bpy.types.NodeSocket): |
||||
default_state = BoolProperty(name="Default State", |
||||
description="This state is the Responder's default", |
||||
default=False) |
||||
|
||||
def draw(self, context, layout, node, text): |
||||
# If this is a RespoderState node and the parent is a Responder, offer the user the |
||||
# ability to make this the default state. |
||||
if self.is_linked and not self.is_output: |
||||
# Before we do anything, see if we need to do a delayed update... |
||||
if node.bl_idname == "PlasmaResponderStateNode": |
||||
parent = node.find_input("whodoneit", "PlasmaResponderNode") |
||||
if parent is not None: |
||||
layout.prop(self, "default_state") |
||||
return |
||||
|
||||
# Still here? Draw the text. |
||||
layout.label(text) |
||||
|
||||
|
||||
class PlasmaResponderStateListNode(PlasmaNodeBase, bpy.types.Node): |
||||
bl_category = "LOGIC" |
||||
bl_idname = "PlasmaResponderStateListNode" |
||||
bl_label = "Responder State List" |
||||
|
||||
def add_state_input(self): |
||||
self.inputs.new("PlasmaRespStateListSocket", str(uuid.uuid4())) |
||||
|
||||
def init(self, context): |
||||
# Inputs will be added by the user |
||||
self.outputs.new("PlasmaRespStateSocket", "Go To State", "gotostate") |
||||
|
||||
def draw_buttons(self, context, layout): |
||||
# This will allow us to add input states on the fly. |
||||
# Caveat: We're only showing this operator in the properties because we need the node |
||||
# to be active in the operator... |
||||
op = layout.operator("node.plasma_add_responder_state", text="Add State", icon="ZOOMIN") |
||||
op.node_name = self.name |
||||
|
||||
|
||||
class PlasmaRespStateListSocket(PlasmaRespStateSocketBase, bpy.types.NodeSocket): |
||||
def draw(self, context, layout, node, text): |
||||
# We'll allow them to delete all their inputs if they want to be stupid... |
||||
props = layout.operator("node.plasma_remove_responder_state", text="", icon="X") |
||||
props.node_name = node.name |
||||
props.socket_name = self.name |
||||
|
||||
|
||||
class PlasmaResponderCommandNode(PlasmaNodeBase, bpy.types.Node): |
||||
bl_category = "LOGIC" |
||||
bl_idname = "PlasmaResponderCommandNode" |
||||
bl_label = "Responder Command" |
||||
|
||||
def init(self, context): |
||||
self.inputs.new("PlasmaRespCommandSocket", "Condition", "whodoneit") |
||||
self.outputs.new("PlasmaMessageSocket", "Message", "msg") |
||||
self.outputs.new("PlasmaRespCommandSocket", "Trigger", "trigger") |
||||
|
||||
|
||||
class PlasmaRespCommandSocket(PlasmaNodeSocketBase, bpy.types.NodeSocket): |
||||
bl_color = (0.451, 0.0, 0.263, 1.0) |
||||
|
@ -0,0 +1,55 @@
|
||||
# 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/>. |
||||
|
||||
import bpy |
||||
from bpy.props import * |
||||
|
||||
class NodeOperator: |
||||
def get_node_tree(self, context): |
||||
space = context.space_data |
||||
if space.type != "NODE_EDITOR": |
||||
raise RuntimeError("Operator '{}' should only be used in the node editor".format(self.bl_idname)) |
||||
return space.node_tree |
||||
|
||||
@classmethod |
||||
def poll(cls, context): |
||||
return context.scene.render.engine == "PLASMA_GAME" |
||||
|
||||
|
||||
class ResponderStateAddOperator(NodeOperator, bpy.types.Operator): |
||||
bl_idname = "node.plasma_add_responder_state" |
||||
bl_label = "Add Responder State Socket" |
||||
|
||||
node_name = StringProperty(name="Node's name", options={"HIDDEN"}) |
||||
|
||||
def execute(self, context): |
||||
tree = self.get_node_tree(context) |
||||
tree.nodes[self.node_name].add_state_input() |
||||
return {"FINISHED"} |
||||
|
||||
|
||||
class ResponderStateRemoveOperator(NodeOperator, bpy.types.Operator): |
||||
bl_idname = "node.plasma_remove_responder_state" |
||||
bl_label = "Remove Responder State Socket" |
||||
|
||||
node_name = StringProperty(name="Node's name", options={"HIDDEN"}) |
||||
socket_name = StringProperty(name="Socket name to remove", options={"HIDDEN"}) |
||||
|
||||
def execute(self, context): |
||||
tree = self.get_node_tree(context) |
||||
node = tree.nodes[self.node_name] |
||||
socket = node.inputs[self.socket_name] |
||||
node.inputs.remove(socket) |
||||
return {"FINISHED"} |
Loading…
Reference in new issue