281 lines
10 KiB
Ruby
Executable File
281 lines
10 KiB
Ruby
Executable File
#
|
|
# File:: data_compare_gta4_episodes.rb
|
|
# Description:: Comparison script to find all new and changed objects over
|
|
# several episodes.
|
|
#
|
|
# Author:: David Muir <david.muir@rockstarnorth.com>
|
|
# 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
|