Files
2025-09-29 00:52:08 +02:00

270 lines
9.1 KiB
Ruby
Executable File

#
# File:: %RS_TOOLSLIB%/Util/anim/ingame/zip_animations.rb
# Description::
#
# Author:: Luke Openshaw <luke.openshaw@rockstarnorth.com>
# Date:: 09 October 2012
#
#-----------------------------------------------------------------------------
# Uses
#-----------------------------------------------------------------------------
require 'RSG.Base.dll'
require 'RSG.Base.Configuration.dll'
require 'RSG.Base.Windows.dll'
require 'RSG.SourceControl.Perforce'
include RSG::Base::Configuration
include RSG::Base::Logging
include RSG::Base::Logging::Universal
include RSG::Base::OS
include RSG::Base::Windows
include RSG::SourceControl::Perforce
require 'mscorlib'
require 'System.Core'
require 'System.Xml'
include System::Collections::Generic
include System::IO
include System::Diagnostics
include System::Xml
require 'pipeline/os/options'
require 'pipeline/monkey/array'
include Pipeline
#-----------------------------------------------------------------------------
# Constants
#-----------------------------------------------------------------------------
OPTIONS = [
LongOption::new( 'rebuild', LongOption::ArgType.None, 'f', 'Rebuild data; ignoring timestamp information.' ),
LongOption::new( 'checkout', LongOption::ArgType.None, 'c', 'Checkout data from p4.' ),
]
def resolve_dictionary_name( dict_dir, sub_index )
dictionary_name = ''
dict_dir = dict_dir.Replace("\\", "/")
dict_dir_tokens = dict_dir.Split('/')
for i in (sub_index + 1)..(dict_dir_tokens.length)
if(i == sub_index + 1)
dictionary_name = dict_dir_tokens[i-1] + "/"
end
dictionary_name = dictionary_name + dict_dir_tokens[i-1]
end
dictionary_name
end
def generate_master_icd_list( master_list_filename, src_dir, dest_dir, log )
result = true
System::IO::File.Delete(master_list_filename) if System::IO::File.Exists(master_list_filename)
directory_list = Directory.GetDirectories(src_dir, "*.*", SearchOption.AllDirectories)
valid_directory_list = []
directory_list.each do | dir |
next if (Directory.GetFiles(dir, "*.clip")).length == 0
# Basic check that there is at least parity between clip/anim count.
if (Directory.GetFiles(dir, "*.clip")).length == Directory.GetFiles(dir, "*.anim").length then
valid_directory_list << dir
else
log.Error("Mismatch of clip/anim count in #{dir}")
result = false
break
end
end
dictionary_name_list = []
src_dir = src_dir.Replace("\\", "/")
sub_index = src_dir.Split('/').length
xml_writer_settings = XmlWriterSettings.new()
xml_writer_settings.Indent = true
xml_writer_settings.IndentChars = "\t"
xml_writer = XmlWriter.Create(master_list_filename, xml_writer_settings)
xml_writer.WriteStartDocument()
xml_writer.WriteStartElement("Assets")
valid_directory_list.each do | dir |
dictionary_name = resolve_dictionary_name(dir, sub_index)
#MPW - Produce the file for debugging but return false so we do not continue
if(dictionary_name_list.include?(dictionary_name))
log.Error("Dictionary name already exists #{dictionary_name}, see log")
result = false
end
dictionary_path = Path.Combine(dest_dir, dictionary_name + ".icd.zip")
xml_writer.WriteStartElement("ZipArchive")
xml_writer.WriteAttributeString("path", dictionary_path)
xml_writer.WriteStartElement("Directory")
xml_writer.WriteAttributeString("path", dir)
xml_writer.WriteEndElement()
xml_writer.WriteEndElement()
dictionary_name_list << dictionary_name
end
xml_writer.WriteEndDocument()
xml_writer.Close()
return result
end
def checkout_files( p4, changelist, file_mapping, log)
main_args = ['-c', changelist.Number.to_s]
second_args = ['-t', '+l']
file_mapping.each do | zip_dictionary |
if p4.Exists(zip_dictionary.DepotFilename)
log.Message("Marking for edit #{zip_dictionary.DepotFilename}")
args = main_args + [zip_dictionary.DepotFilename]
args = System::Array[System::String].new(args)
ret = p4.Run('edit', args)
else
log.Message("Marking for add #{zip_dictionary.DepotFilename}")
args = main_args + ['-f', '-tbinary+Flw', zip_dictionary.LocalFilename]
args = System::Array[System::String].new(args)
ret = p4.Run('add', args)
end
# TODO: Handle errors better. Do we want to bail if there are any?
ret.Messages.each do | msg |
log.Message(msg)
end
log.Message("about to re-open #{zip_dictionary}")
args = second_args + [zip_dictionary.DepotFilename]
args = System::Array[System::String].new(args)
ret = p4.Run('reopen', args)
ret.Messages.each do | msg |
log.Message(msg)
end
end
end
def run( config, rebuild, checkout, log )
src_dir = config.Project.DefaultBranch.Environment.Subst("$(art)/anim/export_mb")
dest_dir = config.Project.DefaultBranch.Environment.Subst("$(export)/anim/ingame/")
master_list_filename = config.Project.DefaultBranch.Environment.Subst("$(export)/anim/ingame/master_icd_list.xml")
p4 = config.Project.SCMConnect()
begin
log.Message("Syncing: #{dest_dir}")
p4.Run( 'sync', true, Path.Combine( dest_dir, '...' ) )
log.Message("Sync complete")
log.Message("Syncing: #{src_dir}")
p4.Run( 'sync', Path.Combine( src_dir, '...' ) )
log.Message("Sync complete")
zip_files = []
changelist = nil
if checkout then
log.Message("Checking out dictionaries...")
zip_files = Directory.GetFiles( dest_dir, "*.icd.zip", SearchOption.AllDirectories )
zip_files_safe = []
zip_files.each do | zip_file |
zip_files_safe << zip_file.gsub( '@', '%40' )
end
file_mapping = FileMapping.Create(p4, System::Array[System::String].new(zip_files_safe))
if file_mapping.count > 0 then
changelistname = 'In-game Animation Dictionaries [Asset Pipeline 3.0]'
changelist = p4.CreatePendingChangelist(changelistname)
checkout_files(p4, changelist, file_mapping, log)
end
log.Message("Check out complete.")
end
if(generate_master_icd_list(master_list_filename, src_dir, dest_dir, log)) then
log.Message("Zipping clip dictionaries...")
ir_exe = config.ToolsRoot + "\\ironlib\\lib\\RSG.Pipeline.Convert.exe"
args = ""
args = args + " --rebuild" if rebuild == true
args = args + " #{master_list_filename}"
ir_exe = config.Environment.Subst(ir_exe)
args = config.Environment.Subst(args)
log.Message("Asset pack command #{ir_exe} #{args}")
startInfo = ProcessStartInfo::new()
startInfo.Arguments = args
startInfo.FileName = ir_exe
startInfo.UseShellExecute = false
proc = System::Diagnostics::Process.Start(startInfo)
proc.WaitForExit()
exit_code = proc.ExitCode
log.Error("Errors zipping animations, see log") if (exit_code != 0)
else
log.Error("Errors generating master icd list") if (exit_code != 0)
end
if checkout then
post_zip_files = Directory.GetFiles( dest_dir, "*.icd.zip", SearchOption.AllDirectories )
new_zip_files = Array::from_clr(post_zip_files).reject { |zip_file| zip_files.include?(zip_file) }
zip_files_safe = []
new_zip_files.each do | zip_file |
zip_files_safe << zip_file.gsub( '@', '%40' )
end
if(zip_files_safe.count > 0) then
file_mapping = FileMapping.Create(p4, System::Array[System::String].new(zip_files_safe))
if file_mapping.count > 0 then
log.Message("Adding new zip files")
log.Message("New files: #{new_zip_files.inspect}")
if changelist == nil then
changelistname = 'In-game Animation Dictionaries [Asset Pipeline 3.0]'
changelist = p4.CreatePendingChangelist(changelistname)
end
checkout_files(p4, changelist, file_mapping, log)
end
end
log.Message("Reverting unchanged dictionaries...")
args = ['-a', Path.Combine( dest_dir, '...' )]
p4.Run('revert', System::Array[System::String].new(args))
end
ensure
p4.Disconnect()
end
end
#-----------------------------------------------------------------------------
# Implementation
#-----------------------------------------------------------------------------
if ( __FILE__ == $0 ) then
#-------------------------------------------------------------------------
# Entry-Point
#-------------------------------------------------------------------------
LogFactory.Initialize()
LogFactory.CreateApplicationConsoleLogTarget( )
g_Log = LogFactory.ApplicationLog
begin
g_Options = OS::Options::new( OPTIONS )
g_Config = RSG::Base::Configuration::ConfigFactory::CreateConfig( )
g_Rebuild = ( g_Options.is_enabled?( 'rebuild' ) )
g_Checkout = ( g_Options.is_enabled?( 'checkout' ) )
g_NoPopups = ( g_Options.is_enabled?( 'nopopups' ) )
# Initialise log and console output.
run( g_Config, g_Rebuild, g_Checkout, g_Log )
LogFactory.ApplicationShutdown()
LogFactory.ShowUniversalLogViewer(LogFactory.ApplicationLogFilename()) if ((not g_NoPopups) and g_Log.HasErrors())
rescue Exception => ex
g_Log.Exception( ex, "Exception during #{__FILE__}: #{ex.message}")
LogFactory.ApplicationShutdown()
LogFactory.ShowUniversalLogViewer(LogFactory.ApplicationLogFilename()) if ((not g_NoPopups) and g_Log.HasErrors())
end
end