Executing MAXScript code from Python with MaxPlus

You can execute MAXScript code from Python using the Core.EvalMAXScript() method.

The following command in Python executes the MAXScript code to print \#aaa to the MAXScript Listener window:

import MaxPlus
MaxPlus.Core.EvalMAXScript("print #aaa")

The following command in MAXScript executes Python, which executes the MAXScript code:

commandString1 = 
"import MaxPlus
MaxPlus.Core.EvalMAXScript(\"print #aaa\")
"
python.execute commandString1

FPValues returned when executing MAXScript code from Python

An FPValue is a single value that is returned when a MAXScript expression is evaluated with MaxPlus. An FPValue wraps various types of values, for example, int, float, object, mesh, and so forth.

You can execute a MAXScript expression using Core.EvalMAXScript() and obtain a return value via FPValue using either:

<FPValue> = MaxPlus.Core.EvalMAXScript(<string>)

or:

res = MaxPlus.FPValue()
evaluation_success = MaxPlus.Core.EvalMAXScript(<string>, res)

If an error occurs while running the MAXScript expression when using the first method signature above, a runtime exception is thrown. When using the second method signature, a value of False is returned and the FPValue contains a String value with the error message.

Use FPValue.Get() to obtain the value stored in the FPValue. This method returns the appropriate Python value type based on the type of value stored in the FPValue. The FPTypeConstants class contains a list of the FPValue types. The FPTypeGetName(<int>) method returns a string corresponding to the supplied type value.

If you run the following:

import MaxPlus
help(MaxPlus.FPTypeConstants)

You obtain, in the MAXScript Listener, a list of FPValue type names and their corresponding constants:

There are some values that can be returned by a MAXScript expression that are not convertible to a value type supported by FPValue. In this case, the actual MAXScript value is returned in the FPValue. There is currently no Python wrapper class for MAXScript values, so calling Get() on such an FPValue results in a runtime error 'unable to find an appropriate get function for type 44'. The FPValue type corresponding to MAXScript values is 44 (FPTypeConstants.Value).

In the following example, Core.EvalMAXScript('$'+node.Name) returns a FPValue, the type of which we obtain via FPValue.GetType(), the type as string we obtain via FPTypeGetName(r.GetType()), and the value of which we obtain via FPValue.Get().

'''
    Demonstrates evaluating a MAXScript expression and getting a node value from it.
'''
import MaxPlus 
obj = MaxPlus.Factory.CreateGeomObject(MaxPlus.ClassIds.Cone) 
obj.ParameterBlock.radius1.Value = 5.0
obj.ParameterBlock.radius2.Value = 10.0
node = MaxPlus.Factory.CreateNode(obj) 
node.Name = 'PythonCone001' 
r = MaxPlus.Core.EvalMAXScript('$'+node.Name) 
print r.GetType(), MaxPlus.FPTypeGetName(r.GetType()), r.Get()

Getting the base type for an FPValue type

For each type, there is a corresponding tab type. For example, there is an Int type, and an IntTab type. IntTab is similar to a tab (or an array) of integer values. The type value for a Tab type is the type value for the base type plus bit 0x0800 (held in variable TYPE_TAB below) being set.

The following code demonstrates how to print the base type for a type by using ~TYPE_TAB.

MaxPlus.FPTypeConstants.IntTab & ~TYPE_TAB prints out the bits other than TYPE_TAB that are set and therefore prints out the base type for Int/IntTab.

import MaxPlus
TYPE_TAB = 0x0800 
print (MaxPlus.FPTypeConstants.Int)  #prints 1
print (MaxPlus.FPTypeConstants.IntTab)  #prints 2049
print (MaxPlus.FPTypeConstants.IntTab & ~TYPE_TAB)  #prints 1, which is the base type for the IntTab type

FPValues And Python Equivalence

FPValues are wrappers for 3ds Max objects, so they are unique even if they point to the same object. For this reason, two FPValues pointing at the same node are considered equal (==) but not identical ("is") in Python. This also applies to non-equivalence, != and "is not" comparisons. The example below illustrates this difference.

import MaxPlus
# create a sphere node
node_name = "my_sphere"
obj = MaxPlus.Factory.CreateGeomObject(MaxPlus.ClassIds.Sphere)
node = MaxPlus.Factory.CreateNode(obj, node_name)
result = MaxPlus.FPValue()
# get one FPValue pointer to the object by running some MAXScript
evaluation_success = MaxPlus.Core.EvalMAXScript('$%s' % node_name, result)
handle1 =  result.Get()
# get a second pointer to the same object
evaluation_success = MaxPlus.Core.EvalMAXScript('$%s' % node_name, result)
handle2 = result.Get()

# this prints True:
print 'Objects are equal: %s' % (handle1 == handle2)
# this prints False:
print 'Objects are not equal: %s' % (handle1 != handle2)
# this prints False:
print 'Objects are identical: %s' % (handle1 is handle2)
# this prints True:
print 'Objects are not identical: %s' % (handle1 is not handle2)

Note: For more information regarding MAXScript, see the MAXScript Help.