# # File:: pipeline/util/autodesk3dsmax.rb # Description:: Autodesk 3dsmax Interface # # Author:: David Muir # Author:: Luke Openshaw # Date:: 7 April 2008 # # Re-written 14/15 June 2010 to use 3dsmaxRegDump executable to dump # information from the registry (.Net app has access to both x64 and x86 # registry on suitable systems as its a x64 app on x64 platforms, x86 # app on x86 platforms). # #---------------------------------------------------------------------------- # Uses #---------------------------------------------------------------------------- require 'pipeline/config/projects' require 'pipeline/os/path' require 'pipeline/os/start' require 'pipeline/os/sysinfo' require 'pipeline/util/application' require 'rexml/document' require 'singleton' #---------------------------------------------------------------------------- # Implementation #---------------------------------------------------------------------------- module Pipeline # # == Description # Autodesk 3dsmax application interface, to determine installed versions, # install directories etc. Essentially a friendly wrapper for 3dsmax for # the Windows Registry that now copes with x86 registry on Windows x64. # class Autodesk3dsmax include Singleton #--------------------------------------------------------------------- # Public Constants #--------------------------------------------------------------------- # Plugin direcotries for different verisons of max VERSION_DIRS = { 0.0 => 'maxBlank', 11.0 => 'max2009', 12.0 => 'max2010', 13.0 => 'max2011', 14.0 => 'max2012' } #--------------------------------------------------------------------- # Public Methods #--------------------------------------------------------------------- # Class constructor ensures we only reg dump once. def initialize( ) init( ) end # # == Description # Return whether any versions of Autodesk's 3dsmax is installed on # the local machine. # def is_installed?( ) ( not ( @native.empty? and @x86.empty? ) ) end # # == Description # Get the root directory for max installations # def get_root_dir( ) "dcc/#{Pipeline::Config::instance().max_options.toolset_mode.to_s}/" end # # == Description # Return an array of installed 3dsmax versions (as floats). # def versions( ) ( @native.keys + @x86.keys ).uniq end # # == Description # Return the latest installed version of Autodesk's 3dsmax on the local # machine - nil if no versions are installed. # def latest_version( ) installed_versions = versions( ) installed_versions.sort!() do |x,y| y <=> x end return installed_versions[0] if installed_versions.size > 0 return nil end # # == Description # Return a Hash of Hashes of installed versions (key) and their install # locations (string path) for all installed 3dsmax versions (if their # installdir is available in the Registry). # # Hash is of the form: # { :x86 => { ... }, :x64 => { ... } } # def installdirs( ) return nil unless is_installed? if ( :x64 == OS::WinSystemInfo::SysType( ) ) then { :x64 => @native, :x86 => @x86 } else { :x86 => @native, :x64 => {} } end end # # == Description # Return Autodesk3dsmax class static log object. # def Autodesk3dsmax::log( ) @@log = Log.new( 'Autodesk3dsmax' ) if ( @@log.nil? ) @@log end private #--------------------------------------------------------------------- # Private Data #--------------------------------------------------------------------- @@log = nil #--------------------------------------------------------------------- # Private Constants #--------------------------------------------------------------------- DCC_COMMON_DIR = 'dcc/common/' REGISTRY_DUMP = OS::Path::combine( 'install', '3dsmaxRegDump.exe' ) REGISTRY_FILE = '3dsmaxRegDump.xml' XML_XPATH_NATIVE_VERSION = 'Applications/Autodesk3dsmax/maxNative/version' XML_XPATH_X86_VERSION = 'Applications/Autodesk3dsmax/maxX86/version' INIT_SCRIPT_X86 = 'rockstarnorthconfiginit.ms' INIT_SCRIPT_X64 = 'rockstarnorthconfiginit64.ms' #--------------------------------------------------------------------- # Private Methods #--------------------------------------------------------------------- # # == Description # This private method runs the 3dsmaxRegDump executable and writes out # our info XML file that is then parsed into an internal structure. # def init( ) begin toolsbin = Pipeline::Config::instance().toolsbin toolstmp = Pipeline::Config::instance().temp() regdump = OS::Path::combine( toolsbin, REGISTRY_DUMP ) xmlout = OS::Path::combine( toolstmp, REGISTRY_FILE ) FileUtils::mkdir_p( toolstmp ) Autodesk3dsmax::log().info( "Starting \"#{regdump} #{xmlout}\"..." ) status, sout, serr = OS::start( "#{regdump} #{xmlout}" ) # Parse our XML file. parse( xmlout ) rescue Exception => ex Autodesk3dsmax::log().exception( ex, 'Unhandled exception during reg dump' ) end end # # == Description # Parse the passed in 3dsmax reg dump XML file; initialising our internal # data ready to be returned by our instance methods. # def parse( filename ) @native = {} @x86 = {} File::open( filename, 'r' ) do |fp| doc = REXML::Document::new( fp ) doc.elements.each( XML_XPATH_NATIVE_VERSION ) do |nativeElem| @native[nativeElem.attributes['id']] = nativeElem.attributes['installdir'] end doc.elements.each( XML_XPATH_X86_VERSION ) do |x86Elem| @x86[x86Elem.attributes['id']] = x86Elem.attributes['installdir'] end end end end end # Pipeline module #---------------------------------------------------------------------------- # Entry (Unit Testing) #---------------------------------------------------------------------------- if ( __FILE__ == $0 ) then autodesk3dsmax = Pipeline::Autodesk3dsmax::instance( ) puts "Autodesk 3dsmax installed?: #{autodesk3dsmax.is_installed?}" autodesk3dsmax.installdirs.each_pair do |platform, dirs| puts "Platform: #{platform}" dirs.each_pair do |version, installdir| puts "\t#{version} => #{installdir}" end end puts "Versions: #{autodesk3dsmax.versions.join('; ')}" puts "Latest: #{autodesk3dsmax.latest_version}" puts "Root dir: #{autodesk3dsmax.get_root_dir()}" end # pipeline/util/autodesk3dsmax.rb