Files
gtav-src/tools_ng/lib/util/compare/data_compare_gta4_episodes.rb
T
2025-09-29 00:52:08 +02:00

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