MAXScript Language Improvements in 3ds Max 7

The following is a description of internal changes and "tweaks" to the MAXScript language in 3ds Max 7. Other than the "What is new..." topic, these changes do not implement new objects, classes, methods or interfaces, but change the way MAXScript works internally. Usually these changes either improve performance or simplify programming.

Node Access Improvements

A node name cache has been implemented. It is used by MAXScript to resolve pathnames (like $box01) to scene nodes. This optimization primarily comes into play with script controllers that use pathnames. In a scene with 5001 nodes and a script controller that references the 5001'th node by name twice, the time for 10000 evaluations of the script controller went from 147 seconds to 1.6 seconds.

A new checkbox was added to the MAXScript tab of the Preference dialog: Use Fast Node Name Lookup.When on, scene node names are cached by MAXScript, resulting in significantly faster resolution of non-wildcard pathname values ($box01) to node values. When off, the scene nodes are enumerated looking for a scene node name that matches the pathname.

An optimization was introduced in 3ds Max 7 that checks to see if a node has already been invalidated before sending out notifications to its dependents that it has been changed. It speeds up complex rigs, especially those that involve the new expose transform helper. It is controlled by the preferences.InvalidateTMOpt System Global variable. When set to true, the optimization is enabled and multiple notifications will not be sent out. When set to false, the animation system behaves as in 3ds Max 6 and earlier. It is enabled by default.

The MakeNameUnique function was changed to use an std::set rather than a Tab<int>. This reduced the time for creating 2500 nodes of the same type from 145 seconds to 71 seconds. If the nodes are renamed as they are being created, time for creating 2500 nodes reduced from 47seconds to 11 seconds.

The getNodeByName function has been significantly enhanced.

Custom Attributes

refs.dependson now returns the Custom Attributes of an object. In versions prior to 3ds Max 7, Custom Attributes were not considered by this method as technically they are not dependent on the object.

classOf will return the custom attribute definition (MSCustAttribDef) if a scripted custom attribute instance is passed. In previous releases, it was returning a MAXClass value.

The visible name of the MAXCustAttrib class was changed from CustAttrib to MAXCustAttrib. Now you can use: 'CustAttrib.classes' to access the custom attribute classes, and test the superclass of custom attributes against CustAttrib.

Added .isPB2Based as a property of custom attribute definition MSCustAttribDef. Already a property of MAXClass and MSPluginClass.

Added .isMSPluginClass as a read-only property of custom attribute definition MSCustAttribDef, MAXClass, and MSPluginClass. MSPluginClass derives from MAXClass and MSCustAttribDef derives from MSPluginClass. Property is true if the class is a MSPluginClass or MSCustAttribDef. See also the previously defined isMSPluginClass() method.

Added .isMSCustAttribClass as a read-only property of custom attribute definition MSCustAttribDef, MAXClass, and MSPluginClass. Property is true if the class is a MSCustAttribDef. See also the previously defined isMSCustAttribClass() method.

Mesh

In versions prior to 3ds Max 7, the user was responsible for re-initializing the mesh to make it valid before calling update. However, most users do not know everything that needs to be done to re-initialize the mesh properly. For this reason, the re-initializing is done when setting the .numfaces or calling the setNumFaces method.

when Change Handler

A when parameters obj change handler now also picks up topological and geometry changes.

The reason for the previous behavior was the following: if obj was a node, the parameter change message from a changing parameter in most modifiers (including Attribute Holder) was being changed by the ModApp to a geometry change message.

Function Publishing System methods NULL values

For FPS methods/properties that take a Material, RefTarg, INode, Object, or Control values, 'undefined' is an accepted value and is converted to NULL.

getMAXFileObjectNames Strings

getMAXFileObjectNames now returns an array of string values, rather than an array of name values. The object names used by mergeMaxFile are case sensitive, and name values are not guaranteed to maintain the case of the string they wrap. See 3ds Max File Loading and Saving.

Macro Recorder

The Macro Recorder Path Analyzer has been changed to ignore references that are either DeleteReference restore objects or MAXScript MAXWrapper values. In the past, if the PathAnalyzer found one of these references before a reference into the scene, no macro recorder output was generated.

InsertItem for MAXPB2ArrayParam Values

The insertItem method has been extended to work with MAXPB2ArrayParam values:

FOR EXAMPLE:

plugin helper testObj
name: "testObj"
classid:#(8788668,86769866)
extends:dummy
(
  parameters main
  (
    mtltab type:#materialtab tabsizevariable:true
  )
)

t1 = testObj parent:b1
append tabtest.materialTab (standard name: "1")
append tabtest.materialTab (standard name: "2")
append tabtest.materialTab (standard name: "3")
insertItem (standard name: "4") tabtest.materialTab 3

Scripted Plugins

The testing of the 'extends' class type in scripted plugins has been fixed, so a scripted plugin can now extend a scripted plugin.

The simpleMod 'map' event handler call is now explicitly disabled if no map event handler is defined. This leads to no real execution speed increase, the first call to the map event handler can return a non-Point3 value that results in the event handler being disabled anyway.

A remap keyword argument was added to scripted plug-in and scripted custom attribute definitions.

This keyword allows parameter names in the definitions to be changed when updating existing definitions. The keyword takes as an argument a two element array, where each element contains an array of string literal or name values. The size of the two arrays must be the same.

The names in the first array are the existing parameter names, and the names in the second array are the new parameter names.

As parameter names are read while migrating existing plugin instances, the parameter names are searched in the first array. If the name is found, the data associated with that parameter is moved to the parameter name in the corresponding location of the second array.

If a parameter name is not found in the first array, the parameter name is not remapped. If the parameter name in the second array does not match a parameter name in the new definition, the parameter data is not moved to the new definition.

String to Boolean Coercion

Coercion of String to Boolean has been added.

Valid string values (case insensitive) for this coercion are:

"on" as booleanClass --> true
"off" as booleanClass --> false
"true" as booleanClass --> true
"false" as booleanClass --> false

All other string values will result in a runtime error

Array to String Coercion

Introduced a MAXScript variable options.printAllElements and a context with printAllElements <bool> do <expr> for controlling whether the complete Array, MeshSelection, BigMatrix, and BigMatrixRowArray is printed or coerced to string, or just the first 20 elements.

Name Values

A copy method was defined for name values. The method returns the same name value. This is needed to support deep copying of arrays in a clean way.

SubAnim Values

New read-only properties .parent and .index have been added to subAnim values. The parent is the true object owning the subAnim, and the index is the subAnim index within that object.

NOTE:

The true object owning the subAnim can be different than what was originally specified when creating the subAnim, and MAXScript automatically hides certain types of subAnims, automatically promoting the subAnims within them.

FOR EXAMPLE:

s=sphere()
sa = s.baseobject[1]
--> SubAnim:Radius
sa.parent
--> ReferenceTarget:ParamBlock
sa.index
--> 1
--The actual owner of the Radius subAnim is the sphere's parameter block.

User Interface Controls

The .text property is now equivalent to the .caption property for all rollout controls that do not define .text separately (for example, the EditText control already has a .text property).Setting a label's text is the same as setting a label's caption. In previous releases, setting the text does not update the UI, but updates the internal .caption value.

The calculation of the construction height of comboBox and dropdown list was improved. The mininum value of the height parameter of comboBox, dropdown list, and listBox controls is now clamped to 1.

#worldUnits is now accepted as a type of Slider, and is equivalent to a type of #float .

Spinner controls with align: #left were not being positioned correctly. Changing the spinner width moves the spinner right or left with part of the spinner frequently outside the rollout width. This has been fixed so that left aligned spinner controls stay put on the left as width changes.

The Group UI control has been fixed to handle controls within the group that use the across: parameter. The bottom of the group is now below the largest control within the group, rather than below the last control within the group.

FOR EXAMPLE:

rollout test "test"
(
  group "Test Group"
  (
    radiobuttons rb_Test labels:#("AA","BB") columns:1 align:#left across:2
    label lb_test "Test Label:" align:#left offset:[40,0]
  )
)
createdialog test width:329

In 3ds Max 6 and earlier versions, the above results in:

In 3ds Max 7, the result looks like:

Rollout event handlers are now accessible as properties of the rollout. For example, <rollout>.open() will call the open handler of the rollout.

Controlling Program Flow

Fix for continue while mapping across node objectsets.

FOR EXAMPLE:

b=box();b2=box parent:b
for o in objects do (print o.name; continue)
for o in $* do (print o.name; continue)

will print only Box01, not Box02 in 3ds Max 6 and earlier.

Now, it prints both.

Getting the Current Exception

New getCurrentException() method returns the text of the current exception in conjunction with a catch() statement.

Miscellaneous Tweaks

no_max_maker was fixed to return MAXNode values instead of MAXRefTarg values for nodes.

If the first argument of getTransformAxis is the value undefined instead of a node, the viewport common axis is returned.

If the Coordinate System Center (returned by getCoordCenter() ) is #local or the Ref Coord System (returned by getRefCoordSys() ) is #local, #parent , or #gimbal , the last calculated common axis is returned.

See Also