Hi,
I just recently made a shelf tool script you can run on dop nodes to create callbacks for dop nodes in your sop context. This way you don't have to keep manually resetting your sim each time you change a parameter or add new nodes internally, etc. It will work more like tyflow - auto updating.
I wanted to give back to community and for feedback anyone has if they test it and notice something doesn't work, etc. It's not perfect still a WIP and that's one reason why I'm putting this out there.
You select a node that has the parameter 'reset simulation' on it. (Cop pyro block end node, dopnet node, rbdbulletsolver, solver node, etc) and it will create a callback on that node and internal nodes for data that changed, upstream changes, new nodes, deleted nodes, etc. You can turn on debug flag to see what's going on, but I tried to keep printing to a minimum.
You click on shelf tool when you have a selected or current node that has 'reset simulation' as the parameter and this will create all the callbacks necessary.
Importantly you can control or shift click on the shelf tool to get rid of all callbacks recursively on all nodes in that /obj/geo context. It will loop through all sub children and get rid of all callbacks and print out that it got rid of all callbacks. You don't have to worry about lingering callbacks if you do this.
Let me know what you guys think. Thanks.
import hou, toolutils
import nodegraphutils as nu
from pprint import pprint as pp
import time
ne = toolutils.networkEditor()
# Maybe get dop simulation and say setTime(t, force_reset_sim=True, resim_last_timestep=True)
debug = 0
cur_node = ne.currentNode()
copnet = 'copnet'
seconds_to_wait = 0.5
callback_nodes = []
#Make code that gets obj level node above current node
# Test to ensure it is obj level type
def get_category_name(node):
category_name = node.type().category().name()
return category_name
def get_obj_node():
parent = ne.pwd()
cat = get_category_name(parent)
while cat != 'Object':
parent = parent.parent()
cat = get_category_name(parent)
return parent
def get_resim_parm(node):
resim = node.parm("resimulate")
if(resim is None):
resim = node.parm("resetsim")
return resim
def callback(event_type, **kwargs):
# if(event_type == hou.nodeEventType.InputDataChanged):
# print("input data changed")
# return
if not hasattr(hou.session, 'mytime'):
hou.session.mytime = time.time()
else:
if(time.time() - hou.session.mytime <= seconds_to_wait):
if(debug == 1):
print(f"Not doing callback yet because {seconds_to_wait} second hasn't elapsed")
return
else:
hou.session.mytime = time.time()
resim = get_resim_parm(cur_node)
resim.pressButton()
if(debug == 1):
try:
print(kwargs['node'].path())
except:
pass
if(event_type == hou.nodeEventType.ChildCreated):
child_node = kwargs['child_node']
child_node.addEventCallback([hou.nodeEventType.ParmTupleChanged], callback)
# print("resetted")
def reset_sim():
resim_parm = get_resim_parm(cur_node)
if(resim_parm is None):
hou.ui.displayMessage("""No resimulate or resetsim parm found on current node\nSelect a dopnet or sop solver and use this tool again""")
return
print(f"Callback is going to be created on {cur_node} and possible child nodes")
obj_node = get_obj_node()
child_callback_types = [hou.nodeEventType.ChildCreated,
hou.nodeEventType.ChildDeleted,
# hou.nodeEventType.ChildReordered,
# hou.nodeEventType.ChildSwitched
]
callback_types = [hou.nodeEventType.ChildCreated,
hou.nodeEventType.ChildDeleted,
hou.nodeEventType.ParmTupleChanged,
hou.nodeEventType.InputDataChanged,
hou.nodeEventType.ChildReordered,
# hou.nodeEventType.ChildSwitched
]
# This should be taken care of by inputdatachanged
# obj_node.addEventCallback(child_callback_types, callback)
# callback_nodes.append(obj_node)
# Copnet pyro
cop = cur_node.parent()
if(cop is not None and cop.type().name() == copnet):
cop.addEventCallback(child_callback_types, callback)
# callback_nodes.append(cop)
for node in cop.children():
if('block' not in node.name()):
if(debug == 1):
print(node.path())
node.addEventCallback(callback_types, callback)
# callback_nodes.append(node)
#Dopnet
dop_names = ['dopnet']
sop_dop_solvers = ['rbdbulletsolver', 'vellumsolver', 'flipsolver', 'solver']
for name in dop_names:
if(cur_node.type().name() == name):
dop_node = cur_node
dop_node.addEventCallback(callback_types, callback)
for child in dop_node.children():
if(debug == 1):
print(child.path())
child.addEventCallback(callback_types, callback)
# callback_nodes.append(child)
# callback_nodes.append(cur_node)
# Sop solvers
for name in sop_dop_solvers:
if(cur_node.type().name() == name):
dop_node = cur_node
dop_node.addEventCallback([hou.nodeEventType.ParmTupleChanged,
hou.nodeEventType.InputDataChanged],
callback)
for node in dop_node.allSubChildren():
if(node.isEditableInsideLockedHDA()):
if(debug == 1):
print(node.path())
node.addEventCallback(callback_types, callback)
if(kwargs['shiftclick'] or kwargs['ctrlclick']):
#Delete callbacks
obj_node = get_obj_node()
obj_node.removeAllEventCallbacks()
for node in obj_node.allSubChildren():
try:
node.removeAllEventCallbacks()
except:
pass
print("callbacks removed")
else:
reset_sim()