299 lines
14 KiB
Ruby
Executable File
299 lines
14 KiB
Ruby
Executable File
#
|
|
# File:: %RS_TOOLSLIB%/pipeline/resourcing/converters/converter_map_scenexml.rb
|
|
# Description:: Map data merge converter.
|
|
#
|
|
# Author:: David Muir <david.muir@rockstarnorth.com>
|
|
# Date:: 22 March 2011
|
|
#
|
|
|
|
#----------------------------------------------------------------------------
|
|
# Uses
|
|
#----------------------------------------------------------------------------
|
|
require 'pipeline/config/projects'
|
|
require 'pipeline/content/content_core'
|
|
require 'pipeline/os/path'
|
|
require 'pipeline/os/start'
|
|
require 'pipeline/resourcing/converter'
|
|
require 'pipeline/scm/perforce'
|
|
require 'pipeline/util/incredibuild_xge'
|
|
include Pipeline
|
|
include Pipeline::Resourcing
|
|
|
|
#----------------------------------------------------------------------------
|
|
# Implementation
|
|
#----------------------------------------------------------------------------
|
|
module Pipeline
|
|
module Resourcing
|
|
module Converters
|
|
|
|
#
|
|
# == Description
|
|
# Map SceneXml converter; inputs are the raw exported SceneXml files and
|
|
# we output the ITYP/IMAP data which is then put into the processed map
|
|
# zip file.
|
|
#
|
|
# This child converter does its work in the 'prebuild'; this means we
|
|
# have the ITYP and IMAP files available for when the merge child
|
|
# converter repacks up the processed zip.
|
|
#
|
|
class MapConverterSceneXml < ChildConverterBase
|
|
|
|
def initialize( project, branch )
|
|
super( project, branch )
|
|
end
|
|
|
|
# Use SceneXml content to generate map metadata.
|
|
def build( maps, &block )
|
|
MapConverter::log().info( "MapConverterSceneXml::build()" )
|
|
@maps_output = {}
|
|
|
|
# Sync dependent data from P4
|
|
Dir::chdir( @project.root ) do
|
|
p4 = SCM::Perforce::new( )
|
|
begin
|
|
p4.connect( )
|
|
sync_pathname = OS::Path::combine( @project.assets, 'maps/scene_overrides', '...' )
|
|
MapConverter::log().info( "Syncing Scene override data from #{sync_pathname}" )
|
|
p4.run_sync( sync_pathname )
|
|
rescue Exception => ex
|
|
MapConverter::log().exception( ex, 'Scene override data sync exception.' )
|
|
ensure
|
|
p4.disconnect( )
|
|
end
|
|
end
|
|
|
|
# Prepare each map ready for the serialisation.
|
|
maps.each do |map|
|
|
@maps_output[map] = {}
|
|
@maps_output[map][:output] = []
|
|
@maps_output[map][:exclude] = []
|
|
|
|
cache_dir = MapConverter::cache_dir( @branch, map )
|
|
|
|
# Clear cache of old metafiles. This is require in case there are
|
|
# fewer streamed IMAP files produced because of map data characteristics
|
|
# or the split algorithm changes.
|
|
meta_files = OS::FindEx::find_files( OS::Path::combine( cache_dir, '*.imap' ) )
|
|
meta_files += OS::FindEx::find_files( OS::Path::combine( cache_dir, '*.ityp' ) )
|
|
FileUtils::rm( meta_files ) if ( meta_files.size > 0 )
|
|
# Exclude meta files; these will be re-added later if serialiser
|
|
# outputs them.
|
|
meta_files.each do |meta_file|
|
|
@maps_output[map][:exclude] << OS::Path::get_filename( meta_file )
|
|
end
|
|
|
|
# Temporarily delete any IPL files.
|
|
ipl_files = OS::FindEx::find_files( OS::Path::combine( cache_dir, '*.ipl' ) )
|
|
FileUtils::rm( ipl_files ) if ( ipl_files.size > 0 )
|
|
# Exclude these from the final output.
|
|
ipl_files.each do |ipl_file|
|
|
@maps_output[map][:exclude] << OS::Path::get_filename( ipl_file )
|
|
end
|
|
# Temporarily delete any IPL files END.
|
|
|
|
# Exclude the occlusion data; this needs to match the MapOcclusion
|
|
# content node processing.
|
|
@maps_output[map][:exclude] << "#{map.name}.occl.zip"
|
|
|
|
@maps_output[map][:ityp] = OS::Path::combine( cache_dir, "#{map.name}.ityp" )
|
|
@maps_output[map][:imap] = OS::Path::combine( cache_dir, "#{map.name}.imap" )
|
|
|
|
# Re-generate the map metadata.
|
|
@maps_output[map][:scenexml_files] = []
|
|
export_definitions = false
|
|
export_instances = false
|
|
map.inputs.each do |input|
|
|
next unless ( input.children.size > 0 )
|
|
|
|
@maps_output[map][:instances] = true if ( map.exportinstances )
|
|
@maps_output[map][:definitions] = true if ( map.exportdefinitions )
|
|
|
|
input.children.each do |child|
|
|
next unless ( child.is_a?( Content::MapSceneXml ) )
|
|
@maps_output[map][:scenexml_files] << child.filename
|
|
end
|
|
end
|
|
end
|
|
|
|
# Execute the serialiser.
|
|
if ( MapConverter::use_xge( maps ) ) then
|
|
build_xge( maps )
|
|
else
|
|
build_local( maps )
|
|
end
|
|
|
|
# Post-serialise; prepare file lists etc for packaging.
|
|
maps.each do |map|
|
|
process = ( ( @maps_output[map].has_key?( :scenexml_files ) ) and ( @maps_output[map][:scenexml_files].size > 0 ) )
|
|
MapConverter::log().error( "Map #{map.name} has no input SceneXml files." ) unless ( process )
|
|
@maps_output[map][:success] = false unless ( process )
|
|
next unless ( process )
|
|
|
|
cache_dir = MapConverter::cache_dir( @branch, map )
|
|
ityp_filenames = OS::FindEx::find_files( OS::Path::combine( cache_dir, '*.ityp' ) )
|
|
imap_filenames = OS::FindEx::find_files( OS::Path::combine( cache_dir, '*.imap' ) )
|
|
@maps_output[map][:output] += ityp_filenames if ( @maps_output[map][:definitions] )
|
|
@maps_output[map][:output] += imap_filenames if ( @maps_output[map][:instances] )
|
|
|
|
# Ensure we don't exclude newly created files.
|
|
ityp_filenames.each do |ityp_file|
|
|
@maps_output[map][:exclude].delete( OS::Path::get_filename( ityp_file ) )
|
|
end
|
|
imap_filenames.each do |imap_file|
|
|
@maps_output[map][:exclude].delete( OS::Path::get_filename( imap_file ) )
|
|
end
|
|
end
|
|
@maps_output
|
|
end
|
|
|
|
#--------------------------------------------------------------------
|
|
# Private
|
|
#--------------------------------------------------------------------
|
|
private
|
|
SERIALISER = '$(toolsbin)/MapExport/MapExportIDEIPL.exe'
|
|
ARGS_DEFS_AND_INSTS = '--nopopups --build $(export) --iplstream $(stream) --ityp $(ityp) --imap $(imap) --unilog $(toolslog)/converter_map_scenexml_$(mapname).ulog'
|
|
ARGS_DEFS_ONLY = '--nopopups --build $(export) --iplstream $(stream) --ityp $(ityp) --unilog $(toolslog)/converter_map_scenexml_$(mapname).ulog'
|
|
ARGS_INSTS_ONLY = '--nopopups --build $(export) --iplstream $(stream) --imap $(imap) --unilog $(toolslog)/converter_map_scenexml_$(mapname).ulog'
|
|
|
|
STATUS_SUCCESS = 0
|
|
|
|
XGE_TOOL_NAME = 'Map_Metadata_Serialiser'
|
|
XGE_TOOL_CAPTION = 'Generating Map Metadata...'
|
|
XGE_TOOL_MASK = '*.ityp,*.imap,*.xml'
|
|
|
|
# Build using local processes only (if XGE isn't installed for example).
|
|
def build_local( maps )
|
|
|
|
maps.each do |map|
|
|
next unless ( @maps_output[map].has_key?( :scenexml_files ) )
|
|
next unless ( @maps_output[map][:scenexml_files].size > 0 )
|
|
|
|
@branch.in_env do |e|
|
|
cache_dir = MapConverter::cache_dir( @branch, map )
|
|
has_asset_combine = ( @parent.maps_output.has_key?( map ) and ( @parent.maps_output[map].has_key?( :asset_combine ) ) )
|
|
MapConverter::log().info( "Asset Combine XML: #{@parent.maps_output[map][:asset_combine]}." )
|
|
|
|
e.add( 'ityp', @maps_output[map][:ityp] )
|
|
e.add( 'imap', @maps_output[map][:imap] )
|
|
e.add( 'stream', cache_dir )
|
|
e.add( 'mapname', map.name )
|
|
e.add( 'toolslog', OS::Path::combine( Globals::instance().toolsroot, 'logs' ) )
|
|
e.add( 'assetcombine', @parent.maps_output[map][:asset_combine] ) if ( has_asset_combine )
|
|
|
|
command = ''
|
|
if ( @maps_output[map][:instances] and @maps_output[map][:definitions] ) then
|
|
command = e.subst( "#{SERIALISER} #{ARGS_DEFS_AND_INSTS} " )
|
|
elsif ( @maps_output[map][:definitions] ) then
|
|
command = e.subst( "#{SERIALISER} #{ARGS_DEFS_ONLY} " )
|
|
elsif ( @maps_output[map][:instances] ) then
|
|
command = e.subst( "#{SERIALISER} #{ARGS_INSTS_ONLY} " )
|
|
else
|
|
MapConverter::log().error( "Map has no definitions or instances?!" )
|
|
next
|
|
end
|
|
command += e.subst( ' --asset_combine $(assetcombine) ' ) if ( has_asset_combine )
|
|
command += @maps_output[map][:scenexml_files].join(' ')
|
|
MapConverter::log().info( "Serialiser command: #{command}" )
|
|
|
|
status, out, err = OS::start( command )
|
|
case ( status.exitstatus.to_i )
|
|
when STATUS_SUCCESS
|
|
MapConverter::log().info( "Map SceneXml processing succeeded." )
|
|
else
|
|
MapConverter::log().error( "Map SceneXml processing failed (#{status.exitstatus})." )
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
# Build using XGE processes.
|
|
def build_xge( maps )
|
|
MapConverter::log().info( "Creating XGE SceneXml packets." )
|
|
|
|
config = Pipeline::Config::instance()
|
|
xge_folder = XGE::get_temp_dir( @project, @branch.name )
|
|
xge_packet_folder = OS::Path::combine( xge_folder, 'maps' )
|
|
filename = OS::Path::combine( xge_packet_folder, 'maps.xml' )
|
|
log_filename = OS::Path::combine( xge_packet_folder, 'maps.log' )
|
|
|
|
MapConverter::log().info( "Creating XGE SceneXml project and tasks." )
|
|
|
|
# Construct XGE Project
|
|
xge_project = XGE::Project::new( "#{@project.uiname} #{@branch.name} Map Metadata Serialisation" )
|
|
xge_taskgroups = {}
|
|
|
|
# Construct XGE Environment and Tools
|
|
xge_env = XGE::Environment::new( 'Environment' )
|
|
xge_env.add_variable( 'BinVar', config.toolsbin )
|
|
xge_env.add_tool( get_xge_tool() )
|
|
|
|
# Create a single task group for all serialiser tasks.
|
|
xge_taskgroup = XGE::TaskGroup::new( 'Map Metadata Serialisation', [], xge_env, xge_env.tools.first, '$(BinVar)' )
|
|
|
|
# Add Tasks for each map.
|
|
maps.each do |map|
|
|
next unless ( @maps_output[map].has_key?( :scenexml_files ) )
|
|
next unless ( @maps_output[map][:scenexml_files].size > 0 )
|
|
|
|
cache_dir = MapConverter::cache_dir( @branch, map )
|
|
has_asset_combine = ( @parent.maps_output.has_key?( map ) and ( @parent.maps_output[map].has_key?( :asset_combine ) ) )
|
|
MapConverter::log().info( "Asset Combine XML: #{@parent.maps_output[map][:asset_combine]}." )
|
|
|
|
task_name = "Map #{map.name}"
|
|
task = XGE::Task::new( task_name, '' )
|
|
task.caption = task_name
|
|
task.inherit_params = false
|
|
|
|
@branch.in_env do |e|
|
|
e.add( 'ityp', @maps_output[map][:ityp] )
|
|
e.add( 'imap', @maps_output[map][:imap] )
|
|
e.add( 'stream', cache_dir )
|
|
e.add( 'mapname', map.name )
|
|
e.add( 'toolslog', OS::Path::combine( Globals::instance().toolsroot, 'logs' ) )
|
|
e.add( 'assetcombine', @parent.maps_output[map][:asset_combine] ) if ( has_asset_combine )
|
|
|
|
if ( @maps_output[map][:instances] and @maps_output[map][:definitions] ) then
|
|
task.parameters = e.subst( "#{ARGS_DEFS_AND_INSTS} " )
|
|
elsif ( @maps_output[map][:definitions] ) then
|
|
task.parameters = e.subst( "#{ARGS_DEFS_ONLY} " )
|
|
elsif ( @maps_output[map][:instances] ) then
|
|
task.parameters = e.subst( "#{ARGS_INSTS_ONLY} " )
|
|
end
|
|
task.parameters += e.subst( ' --asset_combine $(assetcombine) ' ) if ( has_asset_combine )
|
|
task.parameters += @maps_output[map][:scenexml_files].join(' ')
|
|
end
|
|
xge_taskgroup.tasks << task
|
|
end
|
|
xge_project.add_task( xge_taskgroup )
|
|
xge_project.write( filename )
|
|
|
|
result = true
|
|
MapConverter::log().info( "Starting XGE serialisation process." )
|
|
if ( not XGE::start( filename, log_filename ) ) then
|
|
MapConverter::log().error( "Map metadata serialisation failed. Check Build Monitor for errors." )
|
|
|
|
result = false
|
|
if ( not config.user.username.downcase.include?( User::ASSETBUILDER_USER) )
|
|
error_msg = "XGE Map Metadata Serialisation failed. Check Build Monitor or #{log_filename} for errors."
|
|
GUI::MessageBox::error( "XGE Error Notification", error_msg )
|
|
end
|
|
end
|
|
result
|
|
end
|
|
|
|
# Return an XGE::Tool object for the map metadata serialiser command
|
|
# line utility.
|
|
def get_xge_tool( )
|
|
@branch.in_env do |env|
|
|
path = env.subst( SERIALISER )
|
|
XGE::Tool::new( XGE_TOOL_NAME, XGE_TOOL_CAPTION, 'Serialising remotely...', XGE_TOOL_MASK, true, path, '', true )
|
|
end
|
|
end
|
|
end
|
|
|
|
end # Converters module
|
|
end # Resourcing module
|
|
end # Pipeline module
|
|
|
|
# %RS_TOOLSLIB%/pipeline/resourcing/converters/converter_map_scenexml.rb
|