Maxscript, detect if an object is a reference (meaning it has a derived object line in the modifier stack)

Maxscript, detect if an object is a reference (meaning it has a derived object line in the modifier stack)

TurboChiken
Contributor Contributor
2,988 Views
9 Replies
Message 1 of 10

Maxscript, detect if an object is a reference (meaning it has a derived object line in the modifier stack)

TurboChiken
Contributor
Contributor

I've been beating my head against the wall for a couple weeks now, trying to solve this problem. It appears that using Maxscript, if an object has modifiers and the master object has been deleted already, there's no foolproof way to detect if it is a reference clone (has derived object line in the modifier stack). If it doesn't have modifers, you can just check subanim 4 and if it's a "Modified Object", then it is a reference. Or, if the master object hasn't been deleted from the scene yet, you can use InstanceMgr.GetInstances on the reference object, and then check to see if its subAnim[4][subAnim[4].numSubs] is equal to anything in that list, and if so, it's a reference. But if the master has been deleted and the reference has no modifiers, there doesn't seem to be a way. Thoughts?

0 Likes
2,989 Views
9 Replies
Replies (9)
Message 2 of 10

Swordslayer
Advisor
Advisor

If the master was deleted, the line should no longer be there, no? When it's made reference, the part above the line is nested in another derived object so you could do this 

 

findItem (getSubAnimNames $[4]) #Modified_Object > 0

But if the original object was deleted, there won't be a line in stack and you will still get positive result for that.

0 Likes
Message 3 of 10

TurboChiken
Contributor
Contributor

If two references were derived from a master object, and the master is deleted, then those two references still have the line in the stack.

 

Using the subanim[4].name==#Modified_Object test is only foolproof if there's no modifiers on the stack. 

0 Likes
Message 4 of 10

Swordslayer
Advisor
Advisor

@TurboChiken wrote:

Using the subanim[4].name==#Modified_Object test is only foolproof if there's no modifiers on the stack. 


Well, yeah that's useless for many reasons, but that has nothing to do with the code that I posted - that one is querying names of subanims of the subanim instead (hence why I talked about the nested derived objects in the first place),

0 Likes
Message 5 of 10

TurboChiken
Contributor
Contributor

Ah, my apologies, I skimmed over your code too fast and misread it. However, the code you posted only works if the master object has a modifier applied. 

0 Likes
Message 6 of 10

Swordslayer
Advisor
Advisor

So, would it be acceptable to cheat a bit and select the object? 

fn isReference obj = 
(
	setCommandPanelTaskMode #modify
	select obj

	fn getListBoxLength hWnd =
	(
		local LB_GETCOUNT = 0x18B
		windows.sendMessage hWnd LB_GETCOUNT 0 0
	)

	fn getListBoxItemText hWnd i =
	(
		local LB_GETTEXT = 0x189
		local LB_GETTEXTLEN = 0x18A
		local marshal = dotNetClass "System.Runtime.InteropServices.Marshal"

		local len = windows.sendMessage hWnd LB_GETTEXTLEN i 0
		local lParam = marshal.AllocHGlobal (2 * len + 2) asDotNetObject:on
		windows.sendMessage hWnd LB_GETTEXT i (lParam.ToInt64())

		local str = (marshal.PtrToStringAuto lParam asDotNetObject:on).ToString()
		marshal.FreeHGlobal lParam
		return str
	)

	local iGlobal = (dotNetClass "Autodesk.Max.GlobalInterface").Instance
	local commandPanelHWnd = (windows.getHWndData (iGlobal.UtilGetCoreInterface16()).CommandPanelRollup.Hwnd)[7]
	
	local stackHWnd = for wnd in windows.getChildrenHWnd commandPanelHWnd where UIAccessor.getWindowResourceID wnd[1] == 1689 do exit with wnd[1]
	if not isKindOf stackHWnd Number do return undefined

	local stackItemCount = getListBoxLength stackHWnd
	local referenceItem = for i = 0 to stackItemCount - 1 where getListBoxItemText stackHWnd i == "RefObj" do exit with i

	return isKindOf referenceItem Number
)
0 Likes
Message 7 of 10

denisT.MaxDoctor
Advisor
Advisor

I have been messing around with this task a lot and found that only the sdk solution gives an unequivocal result. The above method more or less works if only one node is selected and its stack in the modifier panel. For multiple selection, things are much more complicated and don't have a pure mxs solution (at least I couldn't find).

0 Likes
Message 8 of 10

Serejah
Advocate
Advocate

Is it correct to treat nodes as reference-clones if all of them share same ReferenceTarget:DerivedObject subanim handles?

 

-- uncreatable maxscript class of (dotNetClass "autodesk.max.sclass_id").GenDerivob
dummyclass = 
with undo off
(
	local p = #( point() )
	p[2] = reference p[1]	
	local result = (for r in refs.dependsOn p[2] where r.superclassid == 2 and r.classid[1] == 3 and r.classid[2] == 0 collect r)[1]
	delete p
	if result != undefined then classof result else undefined
)

(
	local handles = #{}
	for s in selection do
	(
		for item in getClassInstances dummyclass target:s where item.numsubs > 0 do
		(			
			sub = getSubAnim item 1
			handles[ 1 + getHandleByAnim sub ] = true
		)
		format "%\n" (getClassInstances dummyclass target:s)
	)
	handles
)

 

 

0 Likes
Message 9 of 10

denisT.MaxDoctor
Advisor
Advisor

if two nodes have at least one identical DerivedObject, these nodes are referenced. But it's possible that referenced nodes have more than one identical DerivedObject.
But! If two nodes doesn't have identical DeriveObject it doesn't mean they cannot be referenced. Because their referencing can by same BaseObject (!)

 

 

0 Likes
Message 10 of 10

TurboChiken
Contributor
Contributor

Ok... so shouldn't the following method for detecting if an object is a reference work in all circumstances? For any given object X:

1. Get a list of all "instances" of X via InstanceMgr.GetInstances()

2. Weed out the self reference, and any actual instances using areNodesInstances(). What's left over is either objects X derives from, or objects derived from X. If we can find just one case of the former, then we know X is a reference and our search is done.

3. Walk through each model Y in the list, and check if X[4][X[4].numSubs]==Y[4]. If one of them does, then we can know X is a reference.

 

 

0 Likes