MAXScript supports a limited form of persistent global variables. You declare a particular global to be persistent and the value it contains is always saved to and restored from scene files as they are opened and closed. Therefore, you can keep direct references to objects in the scene in variables and those references will persist across scene save and reload.
You declare a global variable as persistent by prefacing its declaration with the reserved word persistent
.
SCRIPT
persistent global foo, baz, bar
declares the variables foo
, baz
, and bar
to be persistent. From then on, the values in foo
, baz
, and bar
at the time of a scene save are stored in the .max scene file. When that file is reopened, the values in foo
, baz
, and bar
are restored, with an implicit declaration as persistent globals if they are not so already declared.
The current limitation with persistent global variables is that only certain kinds of values are storable in a scene file, and only those types of values are saved and restored across scene saves and loads.
The supported value classes are: AngleAxis, Array, Boolean, Color, DataPair, Double, Empty, EulerAngles, Float, Integer, Integer64, IntegerPtr, Interval, Matrix3, Name, OK, Point2, Point3, Point4, Quat, Ray, String, Struct, Time, Undefined, Unsupplied, and all the MAXWrapper classes (nodes, modifiers, controllers, materials, and so on). All other types of values restore as the value undefined
.
In the case of Array, only those values in the array that are in the previous list are correctly saved and restored; others appear as undefined
in the restored array.
IntegerPtr loading and saving support was added in 3ds Max 2015. When saving to a previous 3ds Max version, IntegerPtr values will be stored as Integer64 values.
DataPair loading and saving support was added in 3ds Max 2017 Extension 1. When saving to a previous 3ds Max version, DataPair values will be stored as undefined.
Persistent globals are removed from the persistent globals pool when a File > Reset, File > New, or File > Open is performed, but they will remain in memory as ordinary, non-persistent global variables for that MAX session. Subsequently, persistent global variables declared during a MAX session do not "stick around" and get stored with every other file saved during that session.
When merging or XRef-ing in a file (scene/object XRefs are a special case of merge), when reading in persistent global variables,
If the variable being read from the scene file already exists as a persistent global variable, the value of the persistent global is not overwritten. (It was overwritten in versions prior to 3ds Max 8).
If the variable exists as a non-persistent global variable, the global variable's value is overwritten.
If the variable does not exist as a global variable, a non-persistent global variable will be created. The last 2 behaviors are the same as in previous versions of 3ds Max.
If needed, you can install persistent globals in each new file using a #filePreSave
callback. See General Event Callback Mechanism for more information.
However, this behavior also means that variables originally declared as persistent global variables may remain defined as ordinary global variables over multiple scenes while a script is being created or run, yet show up as undefined when these saved scenes are reopened in another MAX session.
Below are two examples illustrating the use of callbacks to handle such situations:
EXAMPLE 1:
If a script requires that a certain critical variable carries its value into new and opened scenes and always exists as a persistent global, the following callbacks would ensure this during File > Reset, File > New and File > Open events:
callbacks.addscript #systemPostNew "persistent global myVar" id:#myTools callbacks.addscript #systemPostReset "persistent global myVar" id:#myTools callbacks.addscript #filePostOpen "persistent global myVar" id:#myTools
The critical variable is simply re-declared, leaving its value unaffected but ensuring that it is saved as a persistent global within the scene.
EXAMPLE 2:
Another case would be a script requiring that a certain critical variable always exist as a persistent global but never carry its current value into other scenes, instead either reverting to a default value for new and opened scenes that don't have the persistent global defined, or restoring the value from opened scenes that do have the persistent global defined. The following callbacks would assign default values to the variable during File > Reset and File > New events, but would only assign a default value during a File > Open event if the persistent global was not already present in the opened file:
callbacks.addscript #systemPostReset "persistent global myVar=0.0" id:#myTools callbacks.addscript #systemPostNew "persistent global myVar=0.0" id:#myTools callbacks.addscript #filePreOpen "myVar=undefined" id:#myTools callbacks.addscript #filePostOpen "if myVar==undefined do (persistent global myVar=0.0)" id:#myTools
During File > Reset and File > New events the critical variable is re-declared and assigned a default value, but during a File > Open event the variable first becomes undefined and is then tested after the file is opened. If that persistent global variable was already present and defined in the scene being opened, the variable would have already been restored as a persistent global variable with its old value. In that case, there's no need to re-declare it as a persistent global since it is already in the persistent global pool and will remain there forever until explicitly removed.
There is one potential problem with both of the above examples: the persistent globals will continue being created by the callbacks for the rest of the current MAX session. Unless this is the desired behavior, this should be avoided by having the created callbacks removed when the script is closed.
FOR EXAMPLE,
if the script exists in a utility or dialog rollout then the associated close event handler should include a "callbacks.removeScripts" command to remove the callbacks.
on myToolsUtility close do (callbacks.removeScripts id:#myTools)
This example also illustrates the advantage of using id: parameter whenever possible. This not only makes removal easy but specific as well, since it avoids accidentally removing callbacks that belong to other scripts.
See General Event Callback Mechanism and Utility and Rollout Properties, Methods, and Event Handlers for more information.
For methods to create, collect, test, show and remove persistent global variables, see the topic Persistents Structure.
MAXWrapper
value, but the class instance is not in the scene, that value is not stored/restored on a file save/load.EXAMPLES:
-- persistents - node only persistent global global_array = #() global_array[1] = b= box() global_array[2] = bm= bend() global_array[3] = sm= standard() global_array[4] = fog() global_array[5] = area() global_array[6] = bezier_float() global_array[7] = br= bricks() global_array[8] = lookat() global_array[9] = blur() global_array[10] = MapScaler() --b.material=sm --addmodifier b bm --sm.diffusemap=br persistents.show() max hold max fetch persistents.show()
REMARKS:
Only the box is in the array after running this script. If the commented lines are run, the material, modifier, and map are also in the array. MAXScript does not do a full reference-tree dump when it outputs its persistent variables, it just outputs RefIDs for MAX objects and so depends on them being dumped as references by the main file save code.