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

238 lines
7.8 KiB
Ruby
Executable File

#
# gamedataloader.rb
# Game Data Loader
#
# Author:: David Muir <david.muir@rockstarnorth.com>
# Date:: 28 February 2008
#
#-----------------------------------------------------------------------------
# Uses
#-----------------------------------------------------------------------------
require 'pipeline/config/projects'
require 'pipeline/content/content_core'
require 'pipeline/content/content_maps'
require 'pipeline/game/mapidefile'
require 'pipeline/game/mapiplfile'
require 'pipeline/os/path'
require 'pipeline/log/log'
require 'pipeline/util/rage'
#-----------------------------------------------------------------------------
# Code
#-----------------------------------------------------------------------------
module Pipeline
module Game
#
# == Description
# This class is a helper class to load a Rockstar North game's data files
# into memory for further processing.
#
# E.g. it can be used to load all map IDE/IPL files for later processing
# by data exporters or statistics tools.
#
class GameDataLoader
class Error < StandardError; end
attr_reader :project # Associated project
attr_reader :project_ides # Hash ide_filename => IDEFile
attr_reader :project_ipls # Hash ipl_filename => IPLFile
attr_reader :project_imgs # Hash img_filename => IMGFile
#---------------------------------------------------------------------
# Virtual Attributes
#---------------------------------------------------------------------
def total_definitions
total = 0
@project_ides.each do |ide_filename, ideobj|
total += ideobj.total_definitions
end
total
end
#---------------------------------------------------------------------
# Constructor
#---------------------------------------------------------------------
#
# Constructor, loads all game definition and placement data using the
# project configuration, based on the game_tag specified.
#
def initialize( project )
@log = Log.new( 'Game Data Loader' )
@project = project
@r = Pipeline::RageUtils.instance()
@project_ides = {}
@project_ipls = {}
@project_imgs = {}
@definitions_cache = {}
# Ensure project and RAGE are properly initialised...
@project.load_config()
@project.load_content()
end
#---------------------------------------------------------------------
# Public Methods
#---------------------------------------------------------------------
#
# Load all project IDE files based on nodes in the project's content
# tree.
#
def load_ides( verbose = false )
puts "Loading Project #{@project.uiname} IDE Files..."
content = @project.content.find_first_group( 'output_inner' )
@project.in_env do |env|
content.walk do |c|
next unless ( c.is_a?( Pipeline::Content::MapImage ) )
c.inputs.each do |input|
next unless ( input.is_a?( Pipeline::Content::Map ) )
next unless ( input.exportdefinitions )
ide_filename = env.subst( OS::Path.combine( c.path, input.name ) + '.ide' )
next unless ::File::exists?( ide_filename )
load_ide_file( ide_filename, verbose )
end
end
end
end
#
# Load all project IPL files based on nodes in the project's content
# tree.
#
def load_ipls( verbose = false )
puts "Loading Project #{@project.uiname} IPL Files..."
content = @project.content.find_first_group( 'output_inner' )
@project.in_env do |env|
content.walk do |c|
next unless ( c.is_a?( Pipeline::Content::MapImage ) )
c.inputs.each do |input|
next unless ( input.is_a?( Pipeline::Content::Map ) )
next unless ( input.exportinstances )
ipl_filename = env.subst( OS::Path.combine( c.path, input.name ) + '.ipl' )
img_filename = env.subst( OS::Path.combine( c.path, input.name ) + '.img' )
next unless ::File::exists?( ipl_filename )
load_ipl_file( ipl_filename, img_filename, verbose )
end
end
end
end
#
# == Description
# Return an IDEDef object for the specified instance object. Return nil
# if not found, or not loaded.
#
def find_def_for_inst( instance )
throw ArgumentError.new( "Specify IPLObjInst object" ) \
unless ( instance.is_a?( IPLObjInst ) )
return @definitions_cache[instance.name] if ( @definitions_cache.has_key?( instance.name ) )
nil
end
#---------------------------------------------------------------------
# Private Attributes
#---------------------------------------------------------------------
private
attr_reader :definition_cache
#---------------------------------------------------------------------
# Private Constants
#---------------------------------------------------------------------
private
IMAGE_MOUNT = 'image:/'
#---------------------------------------------------------------------
# Private Methods
#---------------------------------------------------------------------
private
#
# Load a single IDE file
#
def load_ide_file( map_ide_path, verbose = false )
raise ArgumentError.new( "IDE File #{map_ide_path} does not exist." ) \
unless File.exists?( map_ide_path )
puts "Loading IDE: #{map_ide_path}" if verbose
idefile = MapIDEFile.new( map_ide_path )
@project_ides[map_ide_path] = idefile
# Populate our definition cache for easy lookup later. This
# could be built on first access to find_def_for_inst()
# function.
addToDefCache( idefile )
end
#
# Load IPL file(s) for a specific map section.
#
def load_ipl_file( map_ipl_path, map_img_path, verbose = false )
raise ArgumentError.new( "IPL file #{map_ipl_path} does not exist." ) \
unless File.exists?( map_ipl_path )
raise ArgumentError.new( "IMG file #{map_img_path} does not exist." ) \
unless File.exists?( map_img_path )
puts "Loading IPL: #{map_ipl_path}" if verbose
@project_ipls[map_ipl_path] = MapIPLFile.new( map_ipl_path )
# Load all map image IPLs...
@r.image.mount( map_img_path, IMAGE_MOUNT )
found_files = @r.find_files( "#{IMAGE_MOUNT}*.ipl" )
found_files.each do |file|
if ( @project_ipls.has_key?( "#{IMAGE_MOUNT}#{file}" ) )
@log.warn( "GameDataLoader: IPL File #{file} already loaded." )
next
end
puts "\tLoading sub-IPL: #{IMAGE_MOUNT}#{file}" if verbose
@project_ipls[file] = MapIPLFile.new( "#{IMAGE_MOUNT}#{file}" )
end
end
#
#
#
def addToDefCache( idefile )
raise "idefile not MapIDEFile class." unless MapIDEFile == idefile.class
idefile.object_definitions.each do |obj|
@definitions_cache[obj.name.downcase] = obj
end
idefile.time_object_definitions.each do |obj|
@definitions_cache[obj.name.downcase] = obj
end
end
end
end # Game module
end # Pipeline module
# End of gamedataloader.rb