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

254 lines
11 KiB
Ruby
Executable File

#
# File:: %RS_TOOLSLIB%/pipeline/resourcing/converters/converter_rage_manifest.rb
# Description:: Class to construct PackFileMetadata files.
#
# Author:: David Muir <david.muir@rockstarnorth.com>
# Date:: 26 May 2011
#
#----------------------------------------------------------------------------
# Uses
#----------------------------------------------------------------------------
require 'rexml/document'
include REXML
#----------------------------------------------------------------------------
# Implementation
#----------------------------------------------------------------------------
module Pipeline
module Resourcing
module Converters
#
# == Description
# The PackfileMetadata class represents the metadata file packed into
# the platform RPF files used to describe dependencies and other metainfo
# about the data in the RPF.
#
# In the future this may not be produced in Ruby script.
#
class PackfileMetadata
def initialize( )
@asset_bindings = []
@imap_group_properties = {}
@imap_group_property_types = {}
@imap_dependencies = {}
@imap_dependencies_2 = {}
@imap_dependencies_2_is_interior = []
@ityp_dependencies_2 = {}
@ityp_dependencies_2_is_interior = []
@interior_dependencies = {}
end
def has_data?()
result = ( @asset_bindings.count > 0 or
@imap_group_properties.count > 0 or
@imap_dependencies.size > 0 or
@imap_dependencies_2.size > 0 or
@ityp_dependencies_2.size > 0 or
@interior_dependencies.size > 0 )
result
end
def save( filename )
begin
FileUtils::mkdir_p( OS::Path::get_directory( filename ) )
File::open( filename, 'w' ) do |fp|
document = Document::new
document << XMLDecl::new
root_element = Element::new( 'CPackFileMetaData' )
if @asset_bindings.count > 0 then
bindings_array = root_element.add_element( 'HDTxdBindingArray' )
@asset_bindings.each do |binding|
binding_element = bindings_array.add_element( 'CHDTxdAssetBinding' )
type_element = binding_element.add_element( 'assetType' )
type_element.text = binding[:type]
target_element = binding_element.add_element( 'targetAsset' )
target_element.text = binding[:targetAsset]
dependency_element = binding_element.add_element( 'HDTxd' )
dependency_element.text = binding[:HDTxd]
end
end
if @imap_group_properties.count > 0 then
ipl_groups_element = root_element.add_element( 'MapDataGroups' )
@imap_group_properties.keys.each do |ipl_group_key|
# Create a new IMAP Group
ipl_group_item_element = ipl_groups_element.add_element( 'Item' )
ipl_group_item_name_element = ipl_group_item_element.add_element( 'Name' )
ipl_group_item_name_element.text = ipl_group_key
@imap_group_properties[ipl_group_key].each do |prop_key, prop_value|
# test for whether it's an array
property_element = ipl_group_item_element.add_element( prop_key )
case @imap_group_property_types[prop_key]
when RageConverter::ParcodegenNodeTypes::ArrayType then
prop_value.each do |propArrayItem|
property_array_element = property_element.add_element( 'Item' )
property_array_element.text = propArrayItem
end
when RageConverter::ParcodegenNodeTypes::TextType then
property_element.text = prop_value
when RageConverter::ParcodegenNodeTypes::AttributeType then
property_element.add_attribute("value", prop_value)
else
RageConverter::log().error( "Error during manifest data creation: property #{prop_key} has invalid type #{@imap_group_property_types[prop_key]}" )
end
end
end
end
# Old IMAP dependency system; implemented for interiors initially.
if ( @imap_dependencies.size > 0 ) then
imap_dependency_element = root_element.add_element( 'imapDependencies' )
@imap_dependencies.each_pair do |imap_name, ityp_name|
imap_dependency = imap_dependency_element.add_element( 'Item' )
imap_name_elem = imap_dependency.add_element( 'imapName' )
imap_name_elem.text = imap_name
ityp_name_elem = imap_dependency.add_element( 'itypName' )
ityp_name_elem.text = ityp_name
end
end
# New IMAP dependency system; implemented for all ITYPs required
# by an IMAP.
if ( @imap_dependencies_2.size > 0 ) then
imap_dependency_element = root_element.add_element( 'imapDependencies_2' )
@imap_dependencies_2.each_pair do |imap_name, ityp_names|
imap_depends = imap_dependency_element.add_element( 'Item' )
imap_name_elem = imap_depends.add_element( 'imapName' )
imap_name_elem.text = imap_name
if( @imap_dependencies_2_is_interior.find_index( imap_name ) != nil ) then
manifest_flags_elem = imap_depends.add_element( 'manifestFlags' )
manifest_flags_elem.text = 'INTERIOR_DATA'
end
required_ityps = imap_depends.add_element( 'itypDepArray' )
ityp_names.each do |ityp_name|
ityp_name_elem = required_ityps.add_element( 'Item' )
ityp_name_elem.text = ityp_name
end
end
end
# ITYP dependency system.
if ( @ityp_dependencies_2.size > 0 ) then
ityp_dependency_element = root_element.add_element( 'itypDependencies_2' )
@ityp_dependencies_2.each_pair do |ityp_name, ityp_names|
ityp_depends = ityp_dependency_element.add_element( 'Item' )
ityp_depends_elem = ityp_depends.add_element( 'itypName' )
ityp_depends_elem.text = ityp_name
if( @ityp_dependencies_2_is_interior.find_index( ityp_name ) != nil ) then
manifest_flags_elem = ityp_depends.add_element( 'manifestFlags' )
manifest_flags_elem.text = 'INTERIOR_DATA'
end
required_ityps = ityp_depends.add_element( 'itypDepArray' )
ityp_names.each do |ityp_name|
ityp_name_elem = required_ityps.add_element( 'Item' )
ityp_name_elem.text = ityp_name
end
end
end
# Interior dependency system.
# B* 892520 - static interior bounds
if ( @interior_dependencies.size > 0 ) then
interiors_element = root_element.add_element( 'Interiors' )
@interior_dependencies.each_pair do |interior_name, bounds_names|
item_element = interiors_element.add_element( 'Item' )
name_element = item_element.add_element( 'Name' )
name_element.text = interior_name
bounds_element = item_element.add_element( 'Bounds' )
bounds_names.each do |bounds_name|
bounds_item_element = bounds_element.add_element( 'Item' )
bounds_item_element.text = bounds_name
end
end
end
document << root_element
fmt = REXML::Formatters::Pretty.new()
fmt.compact = true
fmt.write( document, fp )
end
rescue Exception => ex
RageConverter::log( ).exception( ex, "Error generating manifest." )
end
end
# Add a drawable asset binding.
def add_drawable_asset_binding( target, dependency )
@asset_bindings << {
:type => 'AT_DRB',
:targetAsset => OS::Path::get_basename( target ),
:HDTxd => OS::Path::get_basename( dependency )
}
end
# Add a fragment asset binding.
def add_fragment_asset_binding( target, dependency )
@asset_bindings << {
:type => 'AT_FRG',
:targetAsset => OS::Path::get_basename( target ),
:HDTxd => OS::Path::get_basename( dependency )
}
end
# Add a texture dictionary asset binding.
def add_texture_dictionary_asset_binding( target, dependency )
@asset_bindings << {
:type => 'AT_TXD',
:targetAsset => OS::Path::get_basename( target ),
:HDTxd => OS::Path::get_basename( dependency )
}
end
# Add a binding of IPL group name to bounds filenames.
def add_imap_group_property( imap_group_name, property_name, property_value, type )
if nil==@imap_group_properties[imap_group_name] then
@imap_group_properties[imap_group_name] = Hash.new()
end
@imap_group_properties[imap_group_name][property_name] = property_value
@imap_group_property_types[property_name] = type
end
# OLD: Add an Interior IMAP dependency.
def add_imap_dependency( imap_name, ityp_name )
@imap_dependencies[imap_name] = ityp_name
end
# Add an IMAP to multiple-ITYP dependencies.
def add_imap_dependencies( imap_name, ityp_names, is_interior )
throw ArgumentError::new( "Invalid ITYP names argument (#{ityp_names.class})." ) \
unless ( ityp_names.is_a?( Array ) )
@imap_dependencies_2[imap_name] = ityp_names
@imap_dependencies_2_is_interior << imap_name if( is_interior )
end
# Add an ITYP to multiple-ITYP dependencies.
def add_ityp_dependencies( ityp_name, ityp_names, is_interior )
throw ArgumentError::new( "Invalid ITYP names argument (#{ityp_names.class})." ) \
unless ( ityp_names.is_a?( Array ) )
@ityp_dependencies_2[ityp_name] = ityp_names
@ityp_dependencies_2_is_interior << ityp_name if( is_interior )
end
# Add an ITYP to multiple-ITYP dependencies.
def add_interior_dependencies( interior_name, bounds_items )
throw ArgumentError::new( "Invalid bounds_items argument (#{bounds_items.class})." ) \
unless ( bounds_items.is_a?( Array ) )
@interior_dependencies[interior_name] = bounds_items
end
end
end # Converters module
end # Resourcing module
end # Pipeline module
# %RS_TOOLSLIB%/pipeline/resourcing/converters/converter_rage_manifest.rb