Notifications
Clear all

[Closed] Get property type

Okay so this is probably really simple and Im missing where its stated in the maxscript help!

Anyways, I got the selected object (I check to make sure the selection isnt > 1) now that being $ I can get the classof that object. From there I can find all the properties that object has using getPropNames $ which gives me all the property names in an array.

What Im looking to do is find out what type those properties are, bool, float, int from that array so I can create a rollout with the rollout creator dynamically. If its a bool it’ll make a checkbox, if its float or int it’ll create a spinner with the correct type etc.

Now ShowClass will show the properties with their associated type but Im unsure if that would be useful as Id have to go in and cut up some strings and whatnot even if that returns to a variable I can use to do those operations on.

Basically all I need is a name for the property type :curious:

6 Replies

something simple like

classof (getProperty <object> <prop name>)

should work

1 Reply
(@zeboxx2)
Joined: 11 months ago

Posts: 0

Keep in mind that this only works for values that actually exist.

E.g.


 $.modifiers[1]
 Displace:Displace
 getProperty meditmaterials[1] #diffuseMap
 undefined
 classOf (getProperty meditmaterials[1] #diffuseMap)
 UndefinedClass
 

So you can’t use that to dynamically create a mapButton as all the script tells you is that the value is undefined – not what the expected value would be.

Here’s an alternative:


 -- could change this to use by-reference parameters to deal with the two array results
 fn getProps obj = (
 	propString = stringStream ""
 	showproperties obj to:propString
 	propString = propString as string
 	propArray = filterString propString "
"
 	if (propArray.count == 0) then ( return #(#(),#()) )
 	propNamesArray = #(); propNamesArray[propArray.count] = undefined
 	propTypesArray = #(); propTypesArray[propArray.count] = undefined
 
 	for i = 1 to propArray.count do (
 		prop = propArray[i]
 		prop = filterString prop ":"
 		propNamesArray[i] = (subString (sfs.lib.strTrim (filterString prop[1] " ")[1]) 2 -1) as name
 		if (prop.count == 2) then ( propTypesArray[i] = sfs.lib.strTrim prop[2] )
 	)
 	#(propNamesArray,propTypesArray)
 )
 
 fn getPropType obj prop = (
 	props = getProps obj
 	propNames = props[1]
 	propTypes = props[2]
 	propIndex = findItem propNames prop
 	if (propIndex != 0) then ( propTypes[propIndex] )
 	else ( false )
 )
 getPropType $.modifiers[1] #map
 "texturemap"
 

Note that there is a special set of types of parameter values that end in ‘array’… these are of class ArrayParameter and basically work like an array and would have to be accessed as such to enumerate the actual parameters; this applies to the above script as well as Gravey’s method. Each ArrayParameter can only be an array with parameters of the same type, so the above code should tell you what type of data is in the array… e.g. texturemap, percent (float), float, etc.

Also note that some parameters may have spaces in them… it shouldn’t happen, but I’ve seen it happen in at least (older versions of?) DreamScape, parameter “.Pixel Sampler”. The space should be removed for proper access.

==================================================

Edit: just a .NET thingy that makes use of some of this… it doesn’t access the properties, so the ‘spaces in parameter names’ is not dealt with.

Just enter a target (standard script code… e.g ‘$’ or ‘$.material’, etc.) and it will make a nice tree item for that target with all of the parameter names, their values, their value types ( in parentheses for types derived with the above code, curly braces for classOf() ), and class hierarchy if it’s a maxwrapper. The tree branches out for any parameters that have subparameters as well as for ArrayParameters.


fn classGetHierarchy theClass = (
	local classHierarchy = #(theClass)
	while ((theClass = classOf theClass) != classHierarchy[1]) do (
		insertItem theClass classHierarchy 1
	)
	return classHierarchy
)

try(destroyDialog treeview_rollout)catch()
rollout treeview_rollout "Properties Tree" width:512 height:540 (
	dotNetControl tv "TreeView" width:500 height:500 align:#center
	edittext edt_targ "target" across:3
	button btn_add "add"
	button btn_clear "clear"

	fn getProps obj = (
		propString = stringStream ""
		showproperties obj to:propString
		propString = propString as string
		propArray = filterString propString "
"
		if (propArray.count == 0) then ( return #(#(),#()) )
		propNamesArray = #(); propNamesArray[propArray.count] = undefined
		propTypesArray = #(); propTypesArray[propArray.count] = undefined

		for i = 1 to propArray.count do (
			prop = propArray[i]
			prop = filterString prop ":"
			propNamesArray[i] = (subString (sfs.lib.strTrim (filterString prop[1] " ")[1]) 2 -1) as name
			if (prop.count == 2) then ( propTypesArray[i] = sfs.lib.strTrim prop[2] )
		)
		if (isKindOf obj node) then ( join propNamesArray (getPropNames node) )
		#(propNamesArray,propTypesArray)
	)

	fn clearTV = (
		tv.nodes.clear()
	)

	fn hasProperties obj = (
			try (
				local props = getPropNames obj
				classOf props == Array
			)
			catch ( false )
	)
	fn addProps node obj i: = (
		local propData = getProps obj
		local propNames = propData[1]
		local propTypes = propData[2]
		for prop in propNames do (
			local propValue = getProperty obj prop
			local propValueStr
			if (classOf propValue == string) then  ( propValueStr = "\"" + propValue + "\"" )
			else if (classOf propValue == ArrayParameter) then ( propValueStr = "[arrayParameter]" )
			else ( propValueStr = propValue as string )
			local propType = undefined
			local propTypeStr = ""
--			if ((propValue == undefined) OR (classOf propValue == ArrayParameter)) then (
				local propIndex = findItem propNames prop
				local propType = if (propIndex == 0) then ( undefined ) else ( propTypes[propIndex] )
				if (propType == undefined) then (
					propType = (classOf propValue) as string
					propTypeStr = " {" + propType + "}"
				)
				else (
					propTypeStr = " (" + propType + ")"
				)
--			)
			local classHierarchy
			local classHierarchyStr = ""
			if (isKindOf propValue maxWrapper) then (
				classHierarchy = classGetHierarchy propValue
				if (classHierarchy.count >= 2) then (
					for i = (classHierarchy.count - 1) to 1 by -1 do (
						classHierarchyStr += classHierarchy[i] as string + (if (i > 1) then ( " > " ) else ( ""))
					)
				)
				else ( classHierarchyStr = classHierarchy[1] as string )
			)
			if (classHierarchyStr != "") then ( classHierarchyStr = " :: " + classHierarchyStr )
			newNode = node.nodes.add ((prop as string) + " = " + propValueStr + propTypeStr + classHierarchyStr)
			if (hasProperties propValue) then ( addProps newNode propValue )
			if (classOf propValue == ArrayParameter) then (
				propTypeStr = subString propTypeStr 1 ((findString propTypeStr "array") - 2) + ")"
				for i = 1 to propValue.count do (
					propValueStr = propValue[i] as string

					-- horrible code copy/paste that should be a function
					local classHierarchy
					local classHierarchyStr = ""
					if (isKindOf propValue[i] maxWrapper) then (
						classHierarchy = classGetHierarchy propValue[i]
						if (classHierarchy.count >= 2) then (
							for i = (classHierarchy.count - 1) to 1 by -1 do (
								classHierarchyStr += classHierarchy[i] as string + (if (i > 1) then ( " > " ) else ( ""))
							)
						)
						else ( classHierarchyStr = classHierarchy[1] as string )
					)
					if (classHierarchyStr != "") then ( classHierarchyStr = " :: " + classHierarchyStr )
					-- /horrible code copy/paste
			
					local apNode = newNode.nodes.add ((prop as string) + "[" + i as string + "] = " + propValueStr + propTypeStr + classHierarchyStr)
					if (hasProperties propValue[i]) then ( addProps apNode propValue[i] )
					-- apNode.Expand()
				)
			)
			-- newNode.Expand()
		)
	)
	on tv doubleClick arg do (
		hitNode = tv.GetNodeAt (dotNetObject "System.Drawing.Point" arg.x arg.y)
		if hitNode != undefined do ( print hitNode )
	)

	fn addInfo obj = (
		newNode = tv.nodes.add (obj as string)
		addProps newNode obj
		newNode.expand()
	)

	on btn_add pressed do (
--		addInfo (execute edt_targ.text)
		try (addInfo (execute edt_targ.text)); catch()
	)
	on btn_clear pressed do (
		clearTV()
	)
)
createDialog treeview_rollout

Any node you specify as a target is ‘special’ as it adds the common properties for ‘node’ (name, material, target, etc.) although it can’t derive the expected type automatically. So e.g. ‘target’ is “undefined {UndefinedClasS}” unless it actually has a target. Can’t do much about that one other than per-case code.

Yup that did it, thanks :buttrock:

Ahhh very kewl, this alternative you posted seems to be similar to what I was suggesting with the ShowClass. I didnt realize however there might be problems accessing some properties, I am making sure that the property exists in some fashion though by using getPropNames on the selected object.

  I would assume if a diffuse map was present for a material it would also display, then again $ seems to return only the viewport selected and not the material editor selected. If a material is assigned to selected in the viewport I would assume I could access that material as a property and find the type of that property then work my way down to the maps to see which exist using getPropsName.
  
  For eg

 $.material
      01 - Default:Standard
      classOf (getProperty $ "material")
      Standardmaterial
      getPropNames Standardmaterial
      #(#shaderType, #wire, #twoSided, #faceMap, #faceted, #shaderByName, #opacityType, #opacity, #filterColor, #filterMap, #opacityFallOffType, #opacityFallOff, #ior, #wireSize, #wireUnits, #applyReflectionDimming, #dimLevel, #reflectionLevel, #sampler, #samplerQuality, ...)
      
  and...

 classOf (getProperty Standardmaterial "wire")
      -- Error occurred in anonymous codeblock
      --  Frame:
      -- Unknown property: "wire" in Standardmaterial
     getProperty Standardmaterial "opacity"
     -- Unknown property: "opacity" in Standardmaterial
      
 That is very strange, perhaps you are correct and not just for properties that dont exist. Unless theres something Im doing incorrectly :eek:

Edit:


classOf (getProperty $.material "wire")
BooleanClass

Ahhh

In your second example that is returning an unknown property (ah, you’ve edited it!), that is because you are attempting to get the value of a class property, not an instance (an object that has been created from a class) property.

  All classes have properties, obviously, but as the class is not instantiated as an instance (a real object that you can work on) the set/getProperty methods won't work:

mat = $.material -- get the selected object's material
01 - Default:Standard

matClass = (classOf $.material) -- get the class of the selected object's material

StandardMaterial

getProperty mat #wire -- get the current value of the "wire" property of the  selected object's material
true

getProperty matClass  #wire -- get the current value of the "wire" property of the  selected object's material class, StandardMaterial
Unknown property: "wire" in Standardmaterial
  This last example won't work, as you are trying to access properties on a non-instantiated class!
  
  Hope that helps,
  Dave

Ahh that is helpful, that means if I have the properties after using getPropsNames and I have the object I can just use classOf object.property. I guess I shouldnt make the assumption types are different to classes but it does vary from language to language as far as Im aware, like for eg in C# you could use String or string where ones a type and the other is a class/object? Correct me if im wrong

Now I know this though I see the full use of classOf