# # File:: data_compare_gta4_episodes.rb # Description:: Comparison script to find all new and changed objects over # several episodes. # # Author:: David Muir # Date:: 23 July 2009 # #---------------------------------------------------------------------------- # Uses #---------------------------------------------------------------------------- require 'pipeline/config/projects' require 'pipeline/config/project' require 'pipeline/gui/log_window' require 'pipeline/os/getopt' require 'pipeline/os/path' require 'pipeline/util/environment' require 'pipeline/util/rage' include Pipeline require 'REXML/document' include REXML require 'pipeline/util/rexml_write_fix' #---------------------------------------------------------------------------- # Constants #---------------------------------------------------------------------------- OPTIONS = [ [ '--help', '-h', OS::Getopt::BOOLEAN, 'display usage information.' ], [ '--debug', '-d', OS::Getopt::BOOLEAN, 'include log tracing information.' ], [ '--map', '-m', OS::Getopt::REQUIRED, 'only run for the specific map.' ], [ '--output', '-o', OS::Getopt::REQUIRED, 'output directory.' ] ] MOUNT_POINT = 'image:/' SEPARATOR = "-" * 80 # Ruby rox the big one! #---------------------------------------------------------------------------- # Globals #---------------------------------------------------------------------------- $g_Log = nil $g_ProjGTA4 = nil $g_ProjE1 = nil $g_ProjE2 = nil $g_EnvGTA4 = Environment.new() $g_EnvE1 = Environment.new() $g_EnvE2 = Environment.new() $g_MapIndPath = '$(independent)/data/maps/' $g_MapArtPath = '$(art)/models/' #---------------------------------------------------------------------------- # Functions #---------------------------------------------------------------------------- # Return Array of IDR/IFT files within an IMG archive. def get_idr_ift_files_from_img( r, image ) files = [] r.image.mount( image, MOUNT_POINT ) files += r.find_files( OS::Path::combine( MOUNT_POINT, '*.idr' ) ) files += r.find_files( OS::Path::combine( MOUNT_POINT, '*.ift' ) ) r.image.unmount( image ) files end # Return Array of ITD files within an IMG archive. def get_itd_files_from_img( r, image ) files = [] r.image.mount( image, MOUNT_POINT ) files += r.find_files( OS::Path::combine( MOUNT_POINT, '*.itd' ) ) r.image.unmount( image ) files end def write_name_list( xml_node, name, list ) list.each do |obj| xml_node << obj_elem = Element.new( name ) obj_elem.attributes << Attribute.new( 'name', OS::Path::get_basename( obj ) ) end end # Process a single map image (e.g. manhat/manhat09) def process_map( r, mapname, outputdir, log ) gta4_img = OS::Path::combine( $g_EnvGTA4.subst( $g_MapIndPath ), mapname ) + '.img' e1_img = OS::Path::combine( $g_EnvE1.subst( $g_MapIndPath ), mapname ) + '.img' e2_img = OS::Path::combine( $g_EnvE2.subst( $g_MapIndPath ), mapname ) + '.img' gta4_objects = [] gta4_texdicts = [] e1_objects = [] e1_texdicts = [] e2_objects = [] e2_texdicts = [] log.info( "Processing #{mapname}..." ) if ( not ( File::exists?( e1_img ) or File::exists?( e2_img ) ) ) then log.warn( 'Ignoring map because it doesn\'t exist in either episodic project.' ) return [] end if ( File::exists?( gta4_img ) ) then gta4_objects = get_idr_ift_files_from_img( r, gta4_img ) gta4_texdicts = get_itd_files_from_img( r, gta4_img ) end if ( File::exists?( e1_img ) ) then e1_objects = get_idr_ift_files_from_img( r, e1_img ) e1_texdicts = get_itd_files_from_img( r, e1_img ) end e1_objects_new = (e1_objects - (gta4_objects & e1_objects)) e1_objects_changed = (gta4_objects & e1_objects) if ( File::exists?( e2_img ) ) then e2_objects = get_idr_ift_files_from_img( r, e2_img ) e2_texdicts = get_itd_files_from_img( r, e2_img ) end e2_objects_new = (e2_objects - (gta4_objects & e2_objects)) e2_objects_changed = (gta4_objects & e2_objects) e1_e2_objects = ( e1_objects & e2_objects ) # Ruby really rox the big one! e1_e2_texdicts = ( e1_texdicts & e2_texdicts ) # Write Log data log.info( "#{$g_ProjGTA4.uiname} map: #{gta4_img} (#{File::exists?( gta4_img )})" ) log.info( "#{$g_ProjE1.uiname} map: #{e1_img} (#{File::exists?( e1_img )})" ) log.info( "#{$g_ProjE2.uiname} map: #{e2_img} (#{File::exists?( e2_img )})" ) log.info( "GTA4 Objects: #{gta4_objects.size}" ) log.info( "GTA4 TextDicts: #{gta4_texdicts.size}" ) log.info( "E1 Objects: #{e1_objects.size}" ) log.info( "E1 TextDicts: #{e1_texdicts.size}" ) log.info( "E2 Objects: #{e2_objects.size}" ) log.info( "E2 TextDicts: #{e2_texdicts.size}" ) log.warn( "Objects edited in E1 and E2: #{e1_e2_objects.size}" ) if ( e1_e2_objects.size > 0 ) log.warn( "TexDicts edited in E1 and E2: #{e1_e2_texdicts.size}" ) if ( e1_e2_texdicts.size > 0 ) # Write out XML data for loading in MaxScript later. xml_file = OS::Path::combine( outputdir, OS::Path::get_basename( mapname ) ) + '_episode_objects.xml' xml_doc = Document.new( ) xml_doc << XMLDecl.new( ) xml_doc << root = Element.new( 'episodic_objects' ) root << e1_elem = Element.new( 'episode_1' ) root << e2_elem = Element.new( 'episode_2' ) root << shared_elem = Element.new( 'shared' ) e1_elem << e1_obj_elem = Element.new( 'objects' ) e1_elem << e1_tex_elem = Element.new( 'texture_dictionaries' ) e2_elem << e2_obj_elem = Element.new( 'objects' ) e2_elem << e2_tex_elem = Element.new( 'texture_dictionaries' ) shared_elem << shared_obj_elem = Element.new( 'objects' ) shared_elem << shared_tex_elem = Element.new( 'texture_dictionaries' ) write_name_list( e1_obj_elem, 'object', e1_objects ) write_name_list( e1_tex_elem, 'texture_dictionary', e1_texdicts ) write_name_list( e2_obj_elem, 'object', e2_objects ) write_name_list( e2_tex_elem, 'texture_dictionary', e2_texdicts ) write_name_list( shared_obj_elem, 'object', e1_e2_objects ) write_name_list( shared_tex_elem, 'texture_dictionary', e1_e2_texdicts ) File::open( xml_file, 'w' ) do |fp| fmt = REXML::Formatters::Pretty.new() fmt.write( xml_doc, fp ) end # Return some stats for the top-level func to gather overall counts. [ gta4_objects.size, gta4_texdicts.size, e1_objects.size, e1_texdicts.size, e2_objects.size, e2_texdicts.size, e1_e2_objects.size, e1_e2_texdicts.size, ] end # # Process all map images. # def process_all( r, outputdir, log ) log.info( 'Processing all maps...' ) gta4_path = $g_EnvGTA4.subst( $g_MapIndPath ) + "*.img" num_gta4_objs = num_gta4_tex = 0 num_e1_objs = num_e1_tex = 0 num_e2_objs = num_e2_tex = 0 num_e1_e2_objs = num_e1_e2_tex = 0 # Find all GTA4 map img files (get relative so they can be passed # straight into the +process_map+ function. map_files = OS::FindEx::find_files_recurse( gta4_path, true ) log.info( "#{map_files.size} maps to analyse." ) map_files.each do |mapname| res = process_map( r, mapname.sub( '.img', '' ), outputdir, log ) next if ( res.empty? ) num_gta4_objs += res[0] num_gta4_tex += res[1] num_e1_objs += res[2] num_e1_tex += res[3] num_e2_objs += res[4] num_e2_tex += res[5] num_e1_e2_objs += res[6] num_e1_e2_tex += res[7] end log.info( "Total #GTA4 Objects: #{num_gta4_objs}." ) log.info( "Total #GTA4 TexDicts: #{num_gta4_tex}." ) log.info( "Total #E1 Objects: #{num_e1_objs}." ) log.info( "Total #E1 TexDicts: #{num_e1_tex}." ) log.info( "Total #E2 Objects: #{num_e2_objs}." ) log.info( "Total #E2 TexDicts: #{num_e2_tex}." ) log.info( "Total #E1&E2 Objects: #{num_e1_e2_objs}." ) log.info( "Total #E1&E2 TexDicts: #{num_e1_e2_tex}." ) end #---------------------------------------------------------------------------- # Entry-Point #---------------------------------------------------------------------------- if ( __FILE__ == $0 ) then begin g_AppName = OS::Path::get_basename( __FILE__ ) g_Config = Pipeline::Config.instance( ) #--------------------------------------------------------------------- # Parse Command Line #--------------------------------------------------------------------- g_Options, g_Trailing = OS::Getopt::getopts( OPTIONS ) if ( g_Options['help'] ) then puts OS::Getopt::usage( OPTIONS ) exit( 1 ) end g_Debug = g_Options['debug'].nil? ? false : true puts "DEBUG: #{g_Debug}" if ( g_Debug ) g_Config::log_trace = g_Debug g_OutputDir = g_Options['output'].nil? ? OS::Path::get_directory( __FILE__ ) : OS::Path::normalise( g_Options['output'] ) # See if we have a single map to process g_Map = g_Options['map'].nil? ? nil : g_Options['map'] # Force log output Pipeline::Config::instance()::log_level = 2 Pipeline::Config::instance()::log_level = 1 if ( g_Debug ) puts "LEVEL: #{Pipeline::Config::instance()::log_level}" if ( g_Debug ) $g_Log = Log.new( g_AppName ) $g_Log.info( "Output directory: #{g_OutputDir}" ) #--------------------------------------------------------------------- # Process Map(s) #--------------------------------------------------------------------- ##GUI::LogWindow::show_dialog( ) do #----------------------------------------------------------------- # Initialise our global data #----------------------------------------------------------------- $g_ProjGTA4 = g_Config.projects['gta4'] $g_ProjGTA4.load_config() $g_ProjGTA4.fill_env( $g_EnvGTA4 ) $g_Log.info( "#{$g_ProjGTA4.uiname} configuration loaded." ) $g_ProjE1 = g_Config.projects['gta_e1'] $g_ProjE1.load_config() $g_ProjE1.fill_env( $g_EnvE1 ) $g_Log.info( "#{$g_ProjE1.uiname} configuration loaded." ) $g_ProjE2 = g_Config.projects['gta_e2'] $g_ProjE2.load_config() $g_ProjE2.fill_env( $g_EnvE2 ) $g_Log.info( "#{$g_ProjE2.uiname} configuration loaded." ) r = RageUtils.new( $g_ProjGTA4 ) if ( not g_Map.nil? ) then process_map( r, g_Map, g_OutputDir, $g_Log ) else process_all( r, g_OutputDir, $g_Log ) end $g_Log.info( "Done." ) ##end rescue Exception => ex exit( ex.status ) if ( 'exit' == ex.message ) puts "\n#{g_AppName} unhandled exception: #{ex.message}" puts ex.backtrace.join("\n\t") end end # data_compare_all_episodes.rb