From b9381e078e2830cbea676867c430a243c9b450d3 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Tue, 9 Jun 2015 00:47:26 -0400 Subject: [PATCH] Replace RespStateList crazy with a nicer solution Many thanks to Deledrius for pointing out an example of this hackery in Blender's node groups! --- korman/nodes/node_core.py | 33 ++++++++++++-- korman/nodes/node_responder.py | 63 ++++++--------------------- korman/operators/__init__.py | 1 - korman/operators/op_nodes.py | 55 ----------------------- korman/properties/modifiers/region.py | 4 +- 5 files changed, 44 insertions(+), 112 deletions(-) delete mode 100644 korman/operators/op_nodes.py diff --git a/korman/nodes/node_core.py b/korman/nodes/node_core.py index f00e389..574fecb 100644 --- a/korman/nodes/node_core.py +++ b/korman/nodes/node_core.py @@ -51,14 +51,26 @@ class PlasmaNodeBase: 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) + if isinstance(in_key, str): + in_socket = self.find_input_socket(in_key) + else: + in_socket = in_key + if isinstance(out_key, str): + out_socket = node.find_output_socket(out_key) + else: + out_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) + if isinstance(in_key, str): + in_socket = node.find_input_socket(in_key) + else: + in_socket = in_key + if isinstance(out_key, str): + out_socket = self.find_output_socket(out_key) + else: + out_socket = out_key link = tree.links.new(in_socket, out_socket) @classmethod @@ -66,6 +78,19 @@ class PlasmaNodeBase: return (context.bl_idname == "PlasmaNodeTree") +class PlasmaNodeVariableInput(PlasmaNodeBase): + def ensure_sockets(self, idname, name, identifier=None): + """Ensures there is one (and only one) empty input socket""" + empty = [i for i in self.inputs if i.bl_idname == idname and not i.links] + if not empty: + if identifier is None: + self.inputs.new(idname, name) + else: + self.inputs.new(idname, name, identifier) + while len(empty) > 1: + self.inputs.remove(empty.pop()) + + class PlasmaNodeSocketBase: def draw(self, context, layout, node, text): layout.label(text) diff --git a/korman/nodes/node_responder.py b/korman/nodes/node_responder.py index 47e6811..36ed13a 100644 --- a/korman/nodes/node_responder.py +++ b/korman/nodes/node_responder.py @@ -29,67 +29,30 @@ class PlasmaResponderNode(PlasmaNodeBase, bpy.types.Node): self.outputs.new("PlasmaRespStateSocket", "States", "states") -class PlasmaResponderStateNode(PlasmaNodeBase, bpy.types.Node): +class PlasmaResponderStateNode(PlasmaNodeVariableInput, 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", + 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) - + def init(self, context): + self.outputs.new("PlasmaRespCommandSocket", "Commands", "cmds") + self.outputs.new("PlasmaRespStateSocket", "Trigger", "gotostate").link_limit = 1 -class PlasmaResponderStateListNode(PlasmaNodeBase, bpy.types.Node): - bl_category = "LOGIC" - bl_idname = "PlasmaResponderStateListNode" - bl_label = "Responder State List" + def draw_buttons(self, context, layout): + # This actually draws nothing, but it makes sure we have at least one empty input slot + # We need this because it's possible that multiple OTHER states can call us + self.ensure_sockets("PlasmaRespStateSocket", "Condition") - def add_state_input(self): - self.inputs.new("PlasmaRespStateListSocket", str(uuid.uuid4())) + # Now draw a prop + layout.prop(self, "default_state") - 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 PlasmaRespStateSocket(PlasmaNodeSocketBase, bpy.types.NodeSocket): + bl_color = (0.388, 0.78, 0.388, 1.0) class PlasmaResponderCommandNode(PlasmaNodeBase, bpy.types.Node): diff --git a/korman/operators/__init__.py b/korman/operators/__init__.py index bc307e9..f0c38fe 100644 --- a/korman/operators/__init__.py +++ b/korman/operators/__init__.py @@ -16,7 +16,6 @@ from . import op_export as exporter from . import op_lightmap as lightmap from . import op_modifier as modifier -from . import op_nodes as node from . import op_world as world def register(): diff --git a/korman/operators/op_nodes.py b/korman/operators/op_nodes.py deleted file mode 100644 index 6840467..0000000 --- a/korman/operators/op_nodes.py +++ /dev/null @@ -1,55 +0,0 @@ -# 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 . - -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"} diff --git a/korman/properties/modifiers/region.py b/korman/properties/modifiers/region.py index c3c1152..c239eec 100644 --- a/korman/properties/modifiers/region.py +++ b/korman/properties/modifiers/region.py @@ -94,8 +94,8 @@ class PlasmaFootstepRegion(PlasmaModifierProperties, PlasmaModifierLogicWiz): respmod = nodes.new("PlasmaResponderNode") respmod.link_input(tree, logicmod, "trigger", "whodoneit") respstate = nodes.new("PlasmaResponderStateNode") - respstate.link_input(tree, respmod, "states", "whodoneit") - respstate.find_input_socket("whodoneit").default_state = True + respstate.link_input(tree, respmod, "states", respstate.inputs.new("PlasmaRespStateSocket", "Responder")) + respstate.default_state = True respcmd = nodes.new("PlasmaResponderCommandNode") respcmd.link_input(tree, respstate, "cmds", "whodoneit")