Custom Property Migration (XSISDK)

Table of contents

Overview

This article covers topics of how to transition your existing custom properties to a new Self-Installed Custom Property.

Migration from a UI based Custom Property

It is a bit of a manual process to turn a custom property that isn't self-installed into a self-installed custom property. You can use the SDK explorer to list all the parameter ranges and other information. Then you can fill this information into the Custom Property wizard (or edit the _Define() callback code directly). Then you need to delete the original custom property and replace it with an instance of the new Self-installed Custom Property. You may also want to transfer the parameter values and animation from the old property to the new property, for example by writing a script.

Tip: If the order and definition of all the parameters are truly identical then CustomProperty.BinaryData can be used to transfer values from the old property to the new property.

Tip: Starting with XSI v5.0 you can transfer the parameter definitions more easily because the Custom Property Wizard now supports a "Migration" option. To use this feature, inspect the old custom property, right click in the top area and pick Migrate to Self-Installed from the context menu. This will copy all the parameter information, but it does not handle transfering existing values, animations or Proxy Parameters.

Migration of SPDL-based property

If you have an existing SPDL-based Custom Property, you can migrate it to a self-installed custom property.

Each parameter in the SPDL is equivalent to an CustomProperty::AddParameter call in the _Define() section.

Tip: Starting with XSI 5.0 you can populate all the parameters in the Custom Property Wizard automatically. To use this feature, inspect the old custom property, right click in the top area and pick Migrate to Self-Installed from the context menu.

You will also need to re-define the layout using the new API and copy and modify the SPDL logic code. (You need to add a prefix to each callback, e.g.: OnInit will become PROPERTYNAME_OnInit). SPDL Logic was often implemented with VBScript, if you want to change language you will need to do some translation.

Refer to the PSetUIDemo example (http://softimage.wiki.avid.com/sdkdocs/examples/Addons/PSetUIDemo/netview_PSetUIDemo.htm), which includes both a SPDL and Jscript and C++ version of the same property so that the mapping between concepts can be seen.

If the old SPDL was called foo.spdl, there is probably a Preset file called foo.Preset. If you want your new property to have type "Foo" you will need to uninstall the SPDL file, otherwise you will have a conflict. So you probably need to uninstall the SPDL if you want to reuse the same property name. Note: The conflict arises from using the same Type string, there is no problem reusing the same object Name inside the scene.

Migrating the Content of a Scene

Any existing custom properties that were saved from the SPDL version must be deleted and replaced by the new custom property. You can do this with a script that also transfers the parameter values and any fcurves or other attachments.

Here is an example script, you can customize it to your own purposes. It works based on the current scene file but you can also enhance it to load and resave many scene files.

/**********************************************************************
Language: JScript

To use this script:
 - back up your scene
 - install the newly migrated self-installing plugin
 - fill in the values below that are prefixed with "user_"
 - run the script
 - if you didn't opt to have the script delete the existing PSet's then
   they can be selected from the

Copyright Softimage 2005
**********************************************************************/

// ----------------------------------------------------------------------
// Set this value:
//
// the classID of the SPDL based custom PSet that you are migrating away
// from -- it can be found in the SPDL file next to "Reference ="
var user_classIDOfSPDL = "{6CB20CA2-67A9-4C20-8C0A-1CCC594BBE2C}";

// ----------------------------------------------------------------------
// Set this value:
//
// this is the name of the new self-installing paramset that you migrated
// to using the wizard.
var user_typeOfSelfInstalled = "CustomPSet";

// ----------------------------------------------------------------------
// Set this value:
//
// set to true if you want the old PSet deleted, and false if you only 
// want it renamed
var user_delOldPropSet = true;

// ----------------------------------------------------------------------
// Normally this value will not need to be set:
//
// the name of the SPDL based custom PSet that you are migrating away
// from -- it can be found in the SPDL file next to "PropertySet" just before
// the properties are defined.
var user_spdlPropertySetName = "customparamset";


// =====================================================================
// Start running the script

// create the PSet that we will copy/paste to the others
var g_oNewPropSet = null;

// find the props that we need to migrate
var oPropsToMigrate = FindSPDLBasedPropByClassID( user_classIDOfSPDL, user_spdlPropertySetName ) ;

for ( var i = 0 ; i < oPropsToMigrate.Count ; i++ )
{
    MigrateProperty( oPropsToMigrate(i), user_typeOfSelfInstalled, user_delOldPropSet ) ;
}

LogMessage( "Completed." ) ;

// =====================================================================
// Function to only find the "CustomColor" Custom Property
//
function FindSPDLBasedPropByClassID( in_ClassID, in_paramsetName )
{
    // finds all custom param sets -- this GUID returns all of them (not just
    // the one that we specifically want to migrate from)
    var oAllCustomProperties = FindObjects( null, "{76332571-D242-11d0-B69C-00AA003B3EA6}" ) ;

    var oFilteredList = new ActiveXObject( "XSI.Collection" ) ;

    // filter the custom paramset
    for ( var i = 0 ; i < oAllCustomProperties.Count ; i++ )
    {

        if ( oAllCustomProperties(i).Type == in_paramsetName  )
        {
            // Pull out the classID
            var classID= XSIUtils.DataRepository.GetIdentifier( oAllCustomProperties(i), siObjectCLSID ) ;

            if ( classID == in_ClassID )
            {   
                oFilteredList.Add( oAllCustomProperties(i) ) ;
            }
        }
   }
   
   LogMessage ( "Found " + oFilteredList.Count + " instances to migrate." );
   
   for (var i = 0 ; i < oFilteredList.Count ; i++ )
   {
        LogMessage ( i + " - " + oFilteredList(i).FullName ) ;
   }
          
   return oFilteredList ;
}

// =====================================================================
// Copy over the value and any animations from the old PSet to the newly migrated PSet
//
function MigrateProperty( in_oldProp, in_newType, in_delOldProp )
{
    LogMessage( "Migrating " + in_oldProp.FullName ) ;

    // rename the old PSet to backup
    var strName = in_oldProp.Name ;
    in_oldProp.Name = strName + "_Old" ;

    var oParent = in_oldProp.Parent ;
    
    // if filesize of the scene is not overly important, the following if (g_oNewPropSet == null)/else
    // statement can be replaced with just the line to simplify the script:
    //    var oNewProp = oParent.AddProperty( in_newType, false, strName ) ;
	
    // create the new PSet with the old name (only do this once)
    if (g_oNewPropSet == null)
    {
        oNewProp = oParent.AddProperty( in_newType, false, strName ) ;
        g_oNewPropSet = oNewProp ;
    }
    else
    {
        // it's been created once, now copy/paste it for the rest 
        // of the instances
        // - the reason for this is that creating a new custom property each
        //   time (using AddProperty) will make the PSet definition be persisted
        //   with the scene; by copying and pasting, we avoid this problem
        Copy(g_oNewPropSet.FullName);
        Paste(oParent.FullName);
        
        // now populate oNewProp with the object we just pasted in
        oNewProp = GetValue(oParent.FullName + "." + strName);
    }
    
    // Copy values + animation
    var oParamsSrc = in_oldProp.Parameters ;
    var oParamsDest = oNewProp.Parameters ;

    if ( oParamsSrc.Count != oParamsDest.Count )
    {
        LogMessage( "Parameter counts on old and new custom properties don't match", siError ) ;
        return ;
    }
            
    for ( var i = 0 ; i < oParamsSrc.Count ; i++ )
    {
        try
        {
            // We expect both custom properties have the parameters
            // in exactly the same order.  If not then this code
            // would have to be adapted with an extra loop to search 
            // the destination custom property by scripting name
            var oParamSrc = oParamsSrc.Item(i) ;        
            var oParamDest = oParamsDest.Item( i ) ;            
                    
            if ( oParamSrc.ScriptName != oParamDest.ScriptName )
            {
                LogMessage( "Parameters on old and new custom properties don't match " + oParamSrc.ScriptName, siError ) ;
                return ;
            }

            var oSrc = oParamSrc.Source ;
        
            if ( oSrc == null )
            {
                // regular value
                oParamDest.Value = oParamSrc.Value ;
            }
            else if (   ( ClassName(oSrc) == "Expression" )
                     || ( ClassName(oSrc) == "FCurve" ) )
            {
                // this will migrate over the parameters within the PSet that
                // are driven by an external source
                CopyAnimation(oParamSrc.FullName);
                PasteAnimation(oParamDest.FullName);
    
                LogMessage( "Driving PSet param updated..." + oSrc.FullName ) ;
            }
            else if ( ClassName(oSrc) == "Operator" )
            {
                LogMessage( oSrc.FullName + " will have to migrated by hand.  The script does not support Operators." ) ;
            }           
        }   
        catch( e )
        {
            LogMessage( "Unexpected failure transferring value of " + oParamsSrc.Item(i).FullName ) ;
        }       
    }
    
    // Migrate expressions that are driven by this pset
    MigrateExternalExpressions( in_oldProp, oNewProp );
    
    //Remove old property
    if  (in_delOldProp)
    {
        DeleteObj( in_oldProp ) ;
    }
}

// =====================================================================
// Search through the scene to find external parameters whose values are driven
// by a Custom PSet value to migrate them over as well.
// 
// The issue is that XSI correctly updates the expressions when we renamed the old PSet above;
// we have to go back through and set them to the new PSet again
//
function MigrateExternalExpressions( in_oOldPSet, in_oNewPSet )
{
    // This is potentially a slow process
    // At the moment we search the entire 
    // scene recursively:
    var oModel = ActiveSceneRoot ;
    
    // In some cases, if you know all expressions are localized to
    // a model you would use this instead
    // var oModel = oPSet.Model;
    // OR if you know that they are localized to a particular
    // object you could set oModel to point to that object directly 

    //We search for all expressions inside
    //the Model that are driven by this PSet
    var oDrivenParams = oModel.AnimatedParameters( siExpressionSource ) ;

    for ( var i = 0 ; i < oDrivenParams.Count ; i++ )
    {
        var oParam = oDrivenParams.Item(i);     
        var oExpr = oParam.Source ;
                
        try
        {
            //This is the expression string
            var exprDef = oExpr.Parameters( "Definition" ).Value ;
    
            re = new RegExp( in_oOldPSet.Name + "\\." );
    
            if ( exprDef.search( re ) != -1 )
            {
                // Don't need to copy over comment or Active, since they will have remained
                // the same; only the Expr gets updated to reflect the renaming of the old PSet above.
            
                // don't need to worry about l_fcv(), l_interp(), or l_interpOri() -- they store the 
                // object they link to in the EXPR and which has just been updated

                //We found the name of the custom pset in this expression
                //so we know that it is being driven
                SetExpr( oParam.FullName, exprDef.replace(re, in_oNewPSet.Name + ".") );
    
                LogMessage( "Driven parameter updated..." + oParam.FullName ) ;
            }
        }
        catch (e)
        {
            LogMessage ( "Unexpected failure updating animation on external parameter " + oParam.FullName);
        }
    }
}


This page was last modified 14:19, 30 Nov 2005.
This page has been accessed 5649 times.

© Copyright 2009 Autodesk Inc. All Rights Reserved. Privacy Policy | Legal Notices and Trademarks | Report Piracy