308 lines
10 KiB
Ruby
Executable File
308 lines
10 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.' ),
|
|
LongOption::new( 'branch', LongOption::ArgType.Required, 'b', 'Branch name.' ),
|
|
]
|
|
|
|
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 print_return( ret, log)
|
|
ret.Messages.each do | msg |
|
|
log.Message(msg)
|
|
end
|
|
|
|
ret.Errors.each do | msg |
|
|
log.Error(msg)
|
|
end
|
|
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?
|
|
print_return( ret, log)
|
|
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)
|
|
print_return( ret, log)
|
|
end
|
|
|
|
end
|
|
|
|
def run( config, rebuild, checkout, log, branch )
|
|
|
|
dlc_project_art_dirs = []
|
|
dlc_project_export_dirs = []
|
|
dlc_project_master_files = []
|
|
|
|
config.DLCProjects.each do | pair |
|
|
# Avoid patch dlc
|
|
if not pair.Value.Root.include? "patchPacks" then
|
|
if pair.Value.Branches.ContainsKey(branch) then
|
|
dlc_project_art_dirs << pair.Value.Branches[branch].Art + "/anim/export_mb"
|
|
dlc_project_export_dirs << pair.Value.Branches[branch].Export + "/anim/ingame/"
|
|
dlc_project_master_files << pair.Value.Branches[branch].Export + "/anim/ingame/master_icd_list.xml"
|
|
else
|
|
dlc_project_art_dirs << pair.Value.DefaultBranch.Art + "/anim/export_mb"
|
|
dlc_project_export_dirs << pair.Value.DefaultBranch.Export + "/anim/ingame/"
|
|
dlc_project_master_files << pair.Value.DefaultBranch.Export + "/anim/ingame/master_icd_list.xml"
|
|
end
|
|
end
|
|
end
|
|
|
|
p4 = config.Project.SCMConnect()
|
|
changelistname = 'In-game DLC Animation Dictionaries [Asset Pipeline 3.0] - ' + Time.now.to_s
|
|
changelist = p4.CreatePendingChangelist(changelistname)
|
|
|
|
(0..dlc_project_art_dirs.length-1).each do |num|
|
|
|
|
src_dir = dlc_project_art_dirs[num]
|
|
dest_dir = dlc_project_export_dirs[num]
|
|
master_list_filename = dlc_project_master_files[num]
|
|
|
|
begin
|
|
log.Message("Syncing: #{dest_dir}")
|
|
ret = p4.Run( 'sync', true, Path.Combine( dest_dir, '...' ) )
|
|
print_return( ret, log)
|
|
log.Message("Sync complete")
|
|
log.Message("Syncing: #{src_dir}")
|
|
ret = p4.Run( 'sync', Path.Combine( src_dir, '...' ) )
|
|
print_return( ret, log)
|
|
log.Message("Sync complete")
|
|
|
|
if (Directory.Exists( src_dir) == false) then
|
|
next
|
|
end
|
|
|
|
if (Directory.Exists( dest_dir) == false) then
|
|
Directory.CreateDirectory( dest_dir )
|
|
end
|
|
|
|
zip_files = []
|
|
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
|
|
|
|
log.Message(zip_files_safe.length.ToString())
|
|
if(zip_files_safe.length > 0) then
|
|
file_mapping = FileMapping.Create(p4, System::Array[System::String].new(zip_files_safe))
|
|
if file_mapping.count > 0 then
|
|
checkout_files(p4, changelist, file_mapping, log)
|
|
end
|
|
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 + " --branch " + branch
|
|
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}")
|
|
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
|
|
|
|
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_BranchName = ( g_Options.get('branch') )
|
|
g_NoPopups = ( g_Options.is_enabled?( 'nopopups' ) )
|
|
|
|
# Initialise log and console output.
|
|
|
|
run( g_Config, g_Rebuild, g_Checkout, g_Log, g_BranchName )
|
|
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 |