# # File:: %RS_TOOLSLIB%/util/data_convert_file.rb # Description:: Entry-point into our asset build pipeline. # # Author:: David Muir # Date:: 19 March 2012 # #----------------------------------------------------------------------------- # Uses #----------------------------------------------------------------------------- require 'RSG.Base.dll' require 'RSG.Base.Configuration.dll' require 'RSG.Base.Windows.dll' require 'RSG.Pipeline.Core.dll' require 'RSG.Pipeline.Content.dll' require 'RSG.Pipeline.Engine.dll' include RSG::Base::Configuration include RSG::Base::Logging include RSG::Base::Logging::Universal include RSG::Base::OS include RSG::Base::Windows include RSG::Pipeline::Core include RSG::Pipeline::Content include RSG::Pipeline::Engine require 'mscorlib' require 'System.Core' include System::Collections::Generic include System::IO using_clr_extensions System::Linq require 'pipeline/os/options' include Pipeline #----------------------------------------------------------------------------- # Constants #----------------------------------------------------------------------------- AUTHOR = 'RSGEDI Tools' EMAIL = 'RSGEDI Tools <*tools@rockstarnorth.com>' OPTIONS = [ LongOption::new( 'input', LongOption::ArgType.Required, 'i', 'Specify input filename.' ), LongOption::new( 'output', LongOption::ArgType.Required, 'o', 'Specify output filename.' ), LongOption::new( 'recursive', LongOption::ArgType.None, 'r', 'Recurse through input data (for directories).' ), LongOption::new( 'rebuild', LongOption::ArgType.None, 'f', 'Rebuild data; ignoring timestamp information.' ), LongOption::new( 'preview', LongOption::ArgType.None, 'p', 'Preview data; output resources to preview folder.' ), LongOption::new( 'proc', LongOption::ArgType.Required, 'c', 'Define processor to use; defaults to RAGE platform conversion.' ), LongOption::new( 'no-sync', LongOption::ArgType.Required, 's', 'Disable engine Perforce dependency sync.' ), LongOption::new( 'no-xge', LongOption::ArgType.None, 'x', 'Disable Xoreax XGE parallel processing engine.' ), LongOption::new( 'no-content', LongOption::ArgType.None, 'y', 'Disable Content-Tree loading (required for most builds).' ), LongOption::new( 'no-content-cache', LongOption::ArgType.None, 'z', 'Disable Content-Tree cache loading.' ) ] DEFAULT_PROCESSOR = 'RSG.Pipeline.Processor.Platform.Rage' ULOG_VIEWER = '$(toolsbin)/UniversalLogViewer/UniversalLogViewer.exe' ULOG_PATH = '$(toolsroot)/logs' #----------------------------------------------------------------------------- # Functions #----------------------------------------------------------------------------- # None #----------------------------------------------------------------------------- # Entry-Point #----------------------------------------------------------------------------- if ( __FILE__ == $0 ) then # Initialise log and console output. LogFactory.Initialize() LogFactory.CreateApplicationConsoleLogTarget( ) g_Log = LogFactory.ApplicationLog g_Options = OS::Options::new( OPTIONS ) begin if ( g_Options.is_enabled?( 'help' ) ) puts "#{__FILE__}" puts "Usage:" puts g_Options.usage() exit( 1 ) end g_Config = g_Options.command_options.Config g_Project = g_Options.command_options.Project g_BranchName = g_Options.has_option?( 'branch' ) ? g_Options.get( 'branch' ) : g_Project.DefaultBranchName g_Branch = g_Project.Branches[g_BranchName] if ( g_Project.Branches.ContainsKey( g_BranchName ) ) if ( g_Branch.nil? ) then g_Log.Error( "Invalid branch '#{g_BranchName}' for project '#{g_Project.FriendlyName}'." ) exit( 1 ) end # Engine initialisation. g_EngineFlags = EngineFlags.Default g_EngineFlags |= EngineFlags.Rebuild if ( g_Options.is_enabled?( 'rebuild' ) ) g_EngineFlags |= EngineFlags.Preview if ( g_Options.is_enabled?( 'preview' ) ) g_EngineFlags &= ~EngineFlags.SyncDependencies if ( g_Options.is_enabled?( 'no-sync' ) ) g_EngineFlags &= ~EngineFlags.XGE if ( g_Options.is_enabled?( 'no-xge' ) ) g_EngineFlags &= ~EngineFlags.LoadContent if ( g_Options.is_enabled?( 'no-content' ) ) g_EngineFlags &= ~EngineFlags.CacheContent if ( g_Options.is_enabled?( 'no-content-cache' ) ) g_EngineFlags &= ~EngineFlags.Popups unless ( g_Options.show_popups? ) g_Input = g_Options.get( 'input' ) g_Output = g_Options.get( 'output' ) g_Proc = g_Options.get( 'proc' ) g_Proc = DEFAULT_PROCESSOR if ( g_Proc.nil? ) if ( not (g_EngineFlags.HasFlag(EngineFlags.XGE)) ) then g_Log.Warning( "Xoreax XGE parallel processing engine disabled." ) end g_Log.Message( "Engine Flags from user options: #{g_EngineFlags}" ) g_Engine = nil g_BuildTime = nil g_Outputs = nil # Set console title. g_ConsoleTitle = System::Console.Title System::Console.Title = "#{g_Project.FriendlyName}: Asset Build Pipeline, converting: #{g_Options.trailing.join(' ')}" # If we have input and output arguments then that defines the process # to execute; otherwise we fallback to the global convert system to # load the content-tree from disk cache and execute the build. if ( ( not g_Input.nil? ) and ( not g_Output.nil? ) ) g_Engine = Engine::new( g_Options.command_options, g_EngineFlags ) build_input = BuildInput::new( g_Branch ) tree = nil if( not (g_EngineFlags.HasFlag(EngineFlags.LoadContent))) #no-content flag has been passed in tree = Factory::CreateEmptyTree(g_Branch) else tree = Factory::CreateTree(g_Branch, g_Engine.Processors) end input = tree.CreateFile( g_Input, false ) output = tree.CreateFile( g_Output, false ) pb = ProcessBuilder::new( g_Proc, g_Engine.Processors, tree ) pb.Inputs.Add( input ) pb.Outputs.Add( output ) process = pb.ToProcess( ) build_input.RawProcesses.Add( process ) g_Outputs = g_Engine.Build( build_input ) else # If we're not explcitly set up for DLC; then we can override the project # and branch we initialise the Engine with if the filenames passed in are # DLC-related. This is set up here; and allows the convienience of # right-click DLC asset builds. g_Branches = [] g_Filenames = [] g_Options.trailing.each do |filename| g_Filenames << System::IO::Path.GetFullPath( filename ) end g_Filenames = g_Filenames.to_clr( System::String ) if ( not g_Project.IsDLC ) then g_Config.DLCProjects.each do |kvp| g_Filenames.each do |filename| project = kvp.Value project.Branches.each do |kvp2| branch = kvp2.Value if ( branch.IsRootedPath( branch.Export, filename ) or branch.IsRootedPath( branch.Processed, filename ) ) then g_Branches << branch break end end end end end g_Branches = g_Branches.to_clr( RSG::Base::Configuration::IBranch ).Distinct( ) if ( 1 == g_Branches.Count() ) then g_Branch = g_Branches.First() g_Options.command_options.Project = g_Branch.Project g_Options.command_options.Branch = g_Branch g_Log.Message( "Switching project and branch context to: #{g_Branch.Project.FriendlyName} (#{g_Branch.Name})." ) elsif ( g_Branches.Count() > 1 ) then g_Log.Error( "Multiple branch/project files detected. Aborting." ) exit( 1 ) else # Leave our command options as they are. end g_Engine = Engine::new( g_Options.command_options, g_EngineFlags ) g_Outputs = g_Engine.Build( g_Filenames ) end g_BuildTime = g_Outputs[2] g_Log.Message( "Build Took: #{g_BuildTime}" ) exit( g_Outputs[0] ? 0 : 1 ) rescue SystemExit => ex # Show Universal Log output on errors. if ( g_Options.show_popups? and 0 != ex.status ) then command = "#{g_Branch.Environment.Subst(ULOG_VIEWER)} #{LogFactory.ProcessLogDirectory}" g_Log.Message( "Displaying Universal Logs: #{command}" ) system( command ) elsif ( g_Options.show_popups? ) then ## DHM; not sure this is neccessary? ## RSG::Pipeline::Services::MessageBox::Show( "Asset build completed successfully." ) end LogFactory.ApplicationShutdown() exit( ex.status ) rescue Exception => ex g_Log.Exception( ex, "Exception during #{__FILE__}." ) puts "Exception during #{__FILE__}: #{ex.message}" puts ex.backtrace.join("\n") if ( g_Options.show_popups? ) then dlg = RSG::Base::Windows::ExceptionStackTraceDlg::new( ex, g_Config.EmailAddress, AUTHOR, EMAIL ) dlg.ShowDialog( ) end exit( 1 ) end end # %RS_TOOLSLIB%/util/data_convert_file.rb