Notifications
Clear all

[Closed] When object deleted, delete children. Huh?

Also, can someone please tell me why

refs.dependentNodes (custAttributes.getOwner this)

returns the node in question like I want it to, while

custAttributes.getOwner this

returns “Object”?

I can’t figure out what I’m supposed to do with “Object”. It returns the same class as the node, but I can’t delete it, and can’t get a name, id, properties, or anything else off of it.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

when you add a CA to an object you have an option – add it to the node or to node’s baseobject.
owner is the thing where the CA was added.

b = box()
 a = attributes test (;)
 custattributes.add b a baseobject:on
 b.custattributes
 b.baseobject.custattributes
 custattributes.add b a baseobject:off
 b.custattributes

so if you add ca to a baseobject, the owner is baseobject, to get a node you have to ask its first dependent node.

I didn’t think that would actually solve my problem, but figured it was worth a shot.

Anyway, putting what I’ve got from my script back into the context of the code we’ve been using, this is the simplest version of the solution I’ve found. It works until you try to open another scene file, and then it crashes.

2 questions (again in the simplest form possible):
Why does it happen? How do I fix it?

global ContainerAttrib = attributes ContainerAttrib attribID:#(0x1f05aab6, 0x7a59c3a6)
 (
 	local handler
	fn getNode = custattributes.getowner this
 	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.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)
 				attr.container = #()
 			)
 		)
 	)
 	parameters params 
 	(
 		container type:#nodeTab tabsizevariable:on
 		on container set val do constructNode()
 
 		on container tabChanged change do
 		(
 			if change == #refDeleted do
 			(
 				owner = custAttributes.getOwner this
 
 				if handler != undefined do
 				(
 					if (isValidNode owner) and (not isDeleted owner) do
 					(
 						delete owner
 					)
 				)
 			)
 		)
 	)
 
 	on create do constructNode()
 	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 baseObject:false
 			b.container = for k = 1 to num[3] collect (point pos:[k*20,y,0] wirecolor:orange)
 		)
 	)
 	print "DONE!"
 	ok
 )

So okay, I wanted to test out getting rid of the custom attributes before closing the scene to see if that would solve the problem. But… I’m a bit confused about how that is even done. I’d been under the impression that was what custAttributes.deleteDef was for.

First, I found that even after deleting all scene nodes

custAttributes.deleteDef ContainerAttrib

returns

Runtime error: custAttributes.deleteDef - Cannot delete, objects still using this definition: <AttributeDef:ContainerAttrib>

Which doesn’t particularly make sense.

So, I checked out another thread about deleting custom attributes to see if I could find a solution (Denis, you may recognize this one) at http://forums.cgsociety.org/showthread.php?t=1014476

I tried testing out the final script that was posted there, but the attribute definition is still there after it’s deleted. Huh??? How is that even a thing? D:


Apparently, for whatever reason, this is normal behavior for Max, so it looks like I won’t be ableto use this as a solution.

So I’ve stripped it down as far as I can and the problem remains. Why does this work until I try to load a new scene, and then crash?

global ContainerAttrib = attributes ContainerAttrib attribID:#(0x1f05aab6, 0x7a59c3a6)
(
	parameters params 
	(
		cont type:#nodeTab tabsizevariable:on

		on cont tabChanged change do
		(
			if change == #refDeleted do
			(
				owner = custAttributes.getOwner this()

				if owner != undefined do
				(
					if (isValidNode owner) and (not isDeleted owner) do
					(
						delete owner
					)
				)
			)
		)
	)
)

gc()
delete objects
for k = 1 to 2 do
(
	y = (k-1)*20
	global b = dummy name:(uniquename "master") pos:[0,y,0]
	custattributes.add b ContainerAttrib baseObject:false
	b.cont = for k = 1 to 4 collect (point pos:[k*20,y,0] wirecolor:orange)
)

you code tries to delete some nodes which are is about to be deleted by system… it happens on some scene events… brief look at the problem gave this list of events and i disable “auto deletion feature of the CA at the moment of PRE action”

global PreSystem = off
global ContainerAttrib = attributes ContainerAttrib attribID:#(0x1f05aab6, 0x7a59c3a6)
(
	parameters params 
	(
		cont type:#nodeTab tabsizevariable:on

		on cont tabChanged change do if not PreSystem do
		(
			if change == #refDeleted do
			(
				owner = custAttributes.getOwner this
				if (isValidNode owner) and (not isDeleted owner) do
				(
					delete owner
				)
			)
		)
	)
)
fn PreSystemCallback event:#pre = 
(
	PreSystem = (event == #pre)
)
callbacks.removescripts id:#pre_system_flag
callbacks.addscript #filePreOpen "PreSystemCallback event:#pre" id:#pre_system_flag
callbacks.addscript #systemPreNew "PreSystemCallback event:#pre" id:#pre_system_flag
callbacks.addscript #systemPreReset "PreSystemCallback event:#pre" id:#pre_system_flag
callbacks.addscript #preSystemShutdown "PreSystemCallback event:#pre" id:#pre_system_flag

callbacks.addscript #filePostOpen "PreSystemCallback event:#post" id:#pre_system_flag
callbacks.addscript #systemPostNew "PreSystemCallback event:#post" id:#pre_system_flag
callbacks.addscript #systemPostReset "PreSystemCallback event:#post" id:#pre_system_flag
callbacks.addscript #postSystemShutdown "PreSystemCallback event:#post" id:#pre_system_flag

gc()
delete objects
for k = 1 to 2 do
(
	y = (k-1)*20
	global b = dummy name:(uniquename "master") pos:[0,y,0]
	custattributes.add b ContainerAttrib baseObject:false
	b.cont = for k = 1 to 4 collect (point pos:[k*20,y,0] wirecolor:orange)
)

I… actually understand what you did there, which kind of blows my mind. But I definitely would never have figured that out on my own.

So it was either the same problem as with “crash on redo” or else very closely related?

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

that’s a little different. in both cases some nodes are in “predeleted” stage, and cannot be simple delete with “delete” function. both are “predeleted” but are “predeleted” differently. i don’t catch the state in you case yet.

Just want to point some things out really quick, some obvious and some… very weird.

If you save the scene this script creates, restart max, and load the scene up again, deleting any of the point objects throws

-- Error occurred in cont.tabChanged()
--  Frame:
--   PreSystem: undefined
--   change: #refDeleted
--   owner: undefined
>> MAXScript Scripted Plugin Handler Exception:
-- No ""not"" function for undefined <<

Trying to run the script again once this error has been thrown causes the same error to be thrown repeatedly. This persists even after creating a new scene.

Running this portion of the code prior to loading the scene returns functionality:

global PreSystem = off
fn PreSystemCallback event:#pre = 
(
	PreSystem = (event == #pre)
)
callbacks.removescripts id:#pre_system_flag
callbacks.addscript #filePreOpen "PreSystemCallback event:#pre" id:#pre_system_flag
callbacks.addscript #systemPreNew "PreSystemCallback event:#pre" id:#pre_system_flag
callbacks.addscript #systemPreReset "PreSystemCallback event:#pre" id:#pre_system_flag
callbacks.addscript #preSystemShutdown "PreSystemCallback event:#pre" id:#pre_system_flag

callbacks.addscript #filePostOpen "PreSystemCallback event:#post" id:#pre_system_flag
callbacks.addscript #systemPostNew "PreSystemCallback event:#post" id:#pre_system_flag
callbacks.addscript #systemPostReset "PreSystemCallback event:#post" id:#pre_system_flag
callbacks.addscript #postSystemShutdown "PreSystemCallback event:#post" id:#pre_system_flag

Now, going back for a second… I understand why the error occurs initially, that much makes total sense. But I don’t get why the script can no longer be run after that has happened.

To make things even more bizarre, if you run the script one block at a time, no error will be thrown, and the scene will (appear to) work properly. BUT, the scene events in question will once again crash Max!!!

Could you double check if this also happens on your system??

you have the REDO issue. try to select and delete both master and its point, and do undo – redo… max crashes

That’s… not happening for me o.o

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

that is one of the worst situations in the tool development… the bug depends on an order of selection.
try to select a point first and its master after. and delete, undo, redo…

So is that something that can be fixed with another callback?


EDIT:
Actually, I am guessing it has something to do with the fact that the parameter handler does not appear to actually be called on the redo action, at least as evidenced by the following:

		on cont tabChanged change do if not PreSystem do
		(
			format "tabChanged
"

			if change == #refDeleted do 
			(
				owner = custAttributes.getOwner this

				if (isValidNode owner) and (not isDeleted owner) do
				(
					delete owner
				)
			)
		)
Page 6 / 10