When object deleted, delete children. Huh?


#41

what is the other suggestion?


#42

create a something to hold the nodeTab array without actually having anything parented to it, and tell it if the parent node is deleted to delete the rest?

In other words, have one node that is the parent to to the others, and one that holds them all in a nodeTab.


#43

you don’t want to read the help… well…
the idea of the using #nodeTab parameter was almost perfect, but we had a little problem… so let’s just rethink a little. let’s use #maxobjectTab and NodeTransformMonitor objects instead of nodes. capiche?


#44

edit: deleted as doubled


#45

what? the post is doubled. never mind. read the last one


#46

I have no problem reading the help. Part of the reason I brought it up, though, is that I thought doing it the other way would help me more with my other goal, which is to set something up where if ANY of the objects in a collection like this are deleted, then all of the rest will ALSO be deleted.


#47

that’s the simplest part in the our (technically yours) pipeline. the only thing we need is to receive right messages. that’s the thing that we are working on now.
PS: (probably you guess that i have already a completely working solution, but it’s so boring just post it)


#48

I’m sure it’s a lot more fun to watch me flail helplessly.

I promise, I am trying to learn here. Anyway, just swapping things in like this obviously doesn’t work:

global containerAttrib = attributes containerAttrib attribID:#(0x1f05aab6, 0x7a59c3a6)
(
	local handler
	fn constructNode =
	(
		--format "theHold.redoing(): %, theHold.holding(): %
" (theHold.redoing()) (theHold.holding())
		if not (theHold.redoing() or theHold.holding()) do
		(
			node = refs.dependentNodes (custAttributes.getOwner this) firstOnly:on
			if (isValidNode node) and not (isDeleted node) and (handler == undefined) do
			(
				handler =	when node deleted node do
				(
				    if (attr = nodeTransformMonitor node:node) != undefined do
					(
						if attr.handler != undefined do deleteChangeHandler attr.handler
						attr.handler = undefined
						delete (for n in attr.container where isValidNode n and not isDeleted n collect n)
						attr.container = #()
					)
				) -- end handler
			)
		)
	) -- end fn constructNode
	parameters params 
	(
		container type:#maxObjectTab tabSizeVariable:on
		on container set val do constructNode()
	)
	on update do constructNode()
	on load do constructNode()
)

And I don’t know what to do instead because there’s nothing useful in the documentation about working with node transform monitors.


#49

This is very interesting topic.
Denis I really appreciate your contribution an effort for amazing explanation.
Probably this is not perfect way but works for me


global ContainerAttrib = attributes ContainerAttrib attribID:#(0x1f05aab6, 0x7a59c3a6)
(
	local handler
	fn getNode = (refs.dependentnodes (custattributes.getowner this) firstonly:on)
	fn constructNode node: = if not (theHold.Redoing() or theHold.Holding()) do
	(
		if node == unsupplied do node = getNode()
		if isvalidnode node and not isdeleted node and handler == undefined do
		(
			handler = when node deleted node do if (attr = node.baseobject.custattributes[#ContainerAttrib]) != undefined do 
			(
				if attr.handler != undefined do deleteChangeHandler attr.handler
				attr.handler = undefined
				delete (for n in attr.container where isvalidnode n.node and not isdeleted n.node collect n.node)
				attr.container = #()
			)
		)
	)
	parameters params 
	(
		container type:#maxObjectTab tabsizevariable:on
		on container set val do constructNode()
	)

	on update do constructNode()
	on load do constructNode()
)
(
	num = [1,1,10]
	for i=1 to num[1] do 
	(
		gc()
		delete objects
		for k=1 to num[2] do
		(
			y = (k-1)*20
			global b = dummy name:(uniquename "master") pos:[0,y,0]
			custattributes.add b ContainerAttrib
			b.ContainerAttrib.constructNode()
			b.container = for k = 1 to num[3] collect (nodeTransformMonitor node:(point pos:[k*20,y,0] wirecolor:orange parent:b) forwardTransformChangeMsgs:false)
		)
	)
	print "DONE!"
	ok
)


#50

I have a question: Why we need to use for loop with n=[1,1,10] and declare master dummy as global. Can we simply use this concept?


global ContainerAttrib = attributes ContainerAttrib attribID:#(0x1f05aab6, 0x7a59c3a6)
(
	local handler
	fn getNode = (refs.dependentnodes (custattributes.getowner this) firstonly:on)
	fn constructNode node: = if not (theHold.Redoing() or theHold.Holding()) do
	(
		if node == unsupplied do node = getNode()
		if isvalidnode node and not isdeleted node and handler == undefined do
		(
			handler = when node deleted node do if (attr = node.baseobject.custattributes[#ContainerAttrib]) != undefined do 
			(
				if attr.handler != undefined do deleteChangeHandler attr.handler
				attr.handler = undefined
				delete (for n in attr.container where isvalidnode n.node and not isdeleted n.node collect n.node)
				attr.container = #()
			)
		)
	)
	parameters params 
	(
		container type:#maxObjectTab tabsizevariable:on
		on container set val do constructNode()
	)

	on update do constructNode()
	on load do constructNode()
)
(
	gc() ; delete objects
	dm = dummy name:(uniquename "master") pos:[0,0,0]
	custattributes.add dm ContainerAttrib
	dm.ContainerAttrib.constructNode()
	dm.container = for k = 1 to 10 collect (nodeTransformMonitor node:(point pos:[k*20,0,0] wirecolor:orange parent:dm) forwardTransformChangeMsgs:false)
	print "DONE!" ; ok
)


#51

both things are just for easier debugging.

… your code is almost correct. but… because #maxobjectTab can contain any maxobjects when you are deleting nodes you have to check that an item is a NodeTransformMonitor object.

and now the next problem. because a NodeTransformMonitor object don’t pass all messages to dependents we lost when construct mechanics for the container parameter.


#52

So what do you suggest?
For now when I delete master dummy then press Undo and delete again everything works fine.
I newer used “when construct mechanic” :sad:

Edit:

Like this?

delete (for n in attr.container where isKindOf n NodeTransformMonitor and isvalidnode n.node and not isdeleted n.node collect n.node)

#53

global ContainerAttrib = attributes ContainerAttrib attribID:#(0x1f05aab6, 0x7a59c3a6)
(
	local handler
	fn getNode = (refs.dependentnodes (custattributes.getowner this) firstonly:on)
	fn constructNode node: = if not (theHold.Redoing() or theHold.Holding()) do
	(
		if node == unsupplied do node = getNode()
		if isvalidnode node and not isdeleted node and handler == undefined do
		(
			handler = when node deleted node do if (attr = node.baseobject.custattributes[#ContainerAttrib]) != undefined do 
			(
				if attr.handler != undefined do deleteChangeHandler attr.handler
				attr.handler = undefined
				delete (for n in attr.container where isvalidnode n and not isdeleted n collect n)
				--delete (for n in attr.container where iskindof n NodeTransformMonitor and isvalidnode n.node and not isdeleted n.node collect n.node)
				attr.container = #()
			)
		)
	)
	parameters params 
	(
		container type:#nodeTab tabsizevariable:on
--		container type:#maxobjectTab tabsizevariable:on
		on container set val do constructNode()
	)

	fn constructTransform = 
	(
		when parameters container change handleAt:#redrawViews do format "params changed...
"
	)
	on create do constructTransform()

	on update do constructNode()
	on load do constructNode()
)
(
	num = [1,2,4]
	for i=1 to num[1] do 
	(
		gc()
		delete objects
		for k=1 to num[2] do
		(
			y = (k-1)*20
			global b = dummy name:(uniquename "master") pos:[0,y,0]
			custattributes.add b ContainerAttrib
			b.container = for k = 1 to num[3] collect (point pos:[k*20,y,0] wirecolor:orange)
			--in b (b.container = for k = 1 to num[3] collect NodeTransformMonitor node:(point pos:[k*20,y,0] wirecolor:orange))
		)
	)
	print "DONE!"
	ok
)

i returned the code to the nodeTab solution. as you can see any move, link, delete, etc… actions with point fires a parameter changed event (because we constructed it using when parameters container change).
now change the code to the maxobjectTab and NodeTransformMonitor solution. and you will see that our when construct stops working. that’s because NodeTransformMonitor doesn’t notify its dependents about all events.


#54

Are you purposely forgot to parent points to dummy?
I added this line “(point pos:[k*20,y,0] wirecolor:orange parent:b)” which is works but after deleting master and back it with UNDO again max complains about “dependency loop”


#55

i purposely didn’t link points to the dummies. because we can’t link dependents and put them as nodes to master’s nodetab.
that was a reason why we moved from nodetab to maxobjecttab solution.


#56

All right, I’m up to speed up to the point of Gazybara’s version, but I’m not going to be able to figure out what I’m supposed to use in place of the when construct. General event callbacks? Node even system? The question here is not about “is there a way to do it” but “what is the RIGHT way to do it.” I.e. what solution is the fastest, most stable, and uses the least system resources.

The script I have been working on was previously using for this purpose used global variables, node event callbacks, and was overall particularly large and cumbersome. I’m taking it back to formula because of some unpredictable results when undoing and redoing. I do appreciate your help in this, but it would be great if instead of dropping hints you could just show me a working solution.


#57

This works until one of the points gets deleted. I have no idea if I’m even on the right track.

global ContainerAttrib = attributes ContainerAttrib attribID:#(0x1f05aab6, 0x7a59c3a6)
(
	local handler
	fn getNode = (refs.dependentnodes (custattributes.getowner this) firstonly:on)

	fn constructNode node: = if not (theHold.Redoing() or theHold.Holding()) do
	(
		if node == unsupplied do node = getNode()
		if isvalidnode node and not isdeleted node and handler == undefined do
		(
			handler = when node deleted node do if (attr = node.baseobject.custattributes[#ContainerAttrib]) != undefined do 
			(
				if attr.handler != undefined do deleteChangeHandler attr.handler
				attr.handler = undefined
				delete (for n in attr.container where isvalidnode n.node and not isdeleted n.node collect n.node)
				attr.container = #()
			)
		)
	)

	parameters params 
	(
		container type:#maxObjectTab tabsizevariable:on
		on container set val do
		(
			constructNode()
		)
	)

	fn constructTransform = 
	(
		when parameters container change handleAt:#redrawViews do
		(
			for n in container do
			(
				when parameters n.node change handleAt:#redrawViews obj do
				(
					format "% Transform changed
" obj.name
				)
			)
		)
	)
	on load do constructNode()

	on create do
	(
		constructNode()
		constructTransform()
	)

	on update do
	(
		constructNode()
		constructTransform()
	)
)

#58

I’ve still got nothing. :confused:


#59

but thanks to your idea i’ve got the great hierarchically independent node binding interface. i’ve found the terrible bug in the max and fixed it using SDK.


#60

the complete ‘container based’ idea is about 500 lines of my mxs code (plus some c++)…
what does give it to me?

deleting a link of finger deletes whole finger

deleting an arm IK effector deletes all IK related nodes and makes the arm only FK’ed

deleting any ‘key’ bone of a leg/arm/tail hierarchy deletes whole hierarchy

deleting the root deletes whole skeleton(rig)

… etc