← Journal

Using Global Variables in pymxs

Using Global Variables in pymxs

When using pymxs as a scripting language for pipeline purposes in 3ds Max, it's often useful to store variables that persist across script executions. This gives us the ability to maintain state and share data between different tools.

Session Variables

The simplest approach is using MaxScript's global variables through pymxs:

import pymxs
rt = pymxs.runtime

# Set a global variable
rt.execute("global myPipelineData = #()")
rt.myPipelineData.append("some_value")

# Read it later
data = rt.myPipelineData
print(list(data))

This works great for the current session, but what if we need to save those variables with the file?

Persisting Data with the File

There are two main approaches to storing data that persists with the Max file:

1. Using Node User Properties

Store information directly on a node in the scene:

# Store data on a node
node = rt.selection[0]
rt.setUserProp(node, "pipelineVersion", "2.1")
rt.setUserProp(node, "exportSettings", "high_quality")

# Retrieve it later
version = rt.getUserProp(node, "pipelineVersion")
settings = rt.getUserProp(node, "exportSettings")

This is great for object-specific data, but what about scene-level metadata?

2. Using Custom File Properties

Store information in the file's custom properties, which can be read even without opening the file:

# Add custom file properties
rt.fileProperties.addProperty(rt.Name("pipelineVersion"), "2.1")
rt.fileProperties.addProperty(rt.Name("lastExportDate"), "2018-06-26")
rt.fileProperties.addProperty(rt.Name("targetPlatform"), "PC")

# Retrieve individual properties
version = rt.fileProperties.findProperty(rt.Name("pipelineVersion"))
if version:
    value = rt.fileProperties.getPropertyValue(version)
    print(f"Pipeline version: {value}")

Helper Function: Get All Properties as Dict

Here's a handy function that returns all custom file properties as a Python dictionary:

def get_file_properties():
    """Get all custom file properties as a dictionary"""
    properties = {}
    
    # Get the number of custom properties
    num_props = rt.fileProperties.getNumProperties()
    
    for i in range(1, num_props + 1):
        # MaxScript uses 1-based indexing
        prop_name = rt.fileProperties.getPropertyName(i)
        prop_value = rt.fileProperties.getPropertyValue(i)
        
        # Convert MaxScript name to Python string
        properties[str(prop_name)] = str(prop_value)
    
    return properties

# Usage
props = get_file_properties()
for key, value in props.items():
    print(f"{key}: {value}")

Reading Properties from Outside the File

One major advantage of file properties is that you can read them without opening the file:

import pymxs
rt = pymxs.runtime

def read_file_metadata(filepath):
    """Read custom properties from a Max file without opening it"""
    # This requires the file to be in a readable state
    # Note: This is a simplified example
    props = rt.getMAXFileObjectNames(filepath)
    return props

# Useful for pipeline tools that need to scan many files

Best Practices

  1. Use node properties for object-specific data (export settings, LOD info, etc.)
  2. Use file properties for scene-level metadata (version, platform, last export date)
  3. Namespace your properties to avoid conflicts: "pipeline_version" not just "version"
  4. Document your properties so other TAs know what they mean
  5. Validate data when reading - properties might not exist or could be corrupted

Real-World Example: Export Validator

Here's how we use this in our export pipeline:

def validate_scene_for_export():
    """Check if scene is ready for export"""
    props = get_file_properties()
    
    required_props = ["pipelineVersion", "targetPlatform", "assetType"]
    
    for prop in required_props:
        if prop not in props:
            rt.messageBox(f"Missing required property: {prop}")
            return False
    
    # Check version compatibility
    version = props.get("pipelineVersion")
    if version != "2.1":
        rt.messageBox(f"Scene version {version} not compatible with exporter 2.1")
        return False
    
    return True

This approach has been invaluable for maintaining consistency across our asset pipeline and catching issues before they reach the engine.

Further Reading

For more details on the pymxs API, check out the official documentation: Autodesk 3ds Max Python API