Files
gtav-src/tools_ng/techart/script/Ruby/Utils/TerrainTiles/TerrainTiles.rb
T
2025-09-29 00:52:08 +02:00

382 lines
10 KiB
Ruby
Executable File

#
#
# Author:: Mark Harrison-Ball <Mark.Harrison-Ball@rockstargames.com>
# Date:: 21 November 2014 (AP3)
# Purpose:
# This is to parse the map terrain files and determine which cutscenes play in which tile
#
# $NAME = GLobal Value
# @NAME = Ruby Instance Variables:
# @@NAME = Ruby Class Variables, must be initialized
# NAME = Ruby Constants, Constants defined within a class or module can be accessed from within that class or module, and those defined outside a class or module can be accessed globally
# read interior xml, then read the level containers
# pass in cutscene position and determine if its in the bound, so we need to do a bound check
# For now we will just the Milo position and work on a bias on the number compared to the scene posiiton
#!/usr/bin/ruby
path = File.expand_path $0
path = File.dirname(path)
require 'System.Xml'
require 'System.Xml.Linq'
require 'RSG.Base.dll'
require 'RSG.Base.Configuration.dll'
include System::Xml
include System::Xml::Linq
include RSG::Base::Configuration
include RSG::Base::Logging
include RSG::Base::Logging::Universal
#using_clr_extensions System::Linq
using_clr_extensions System::Xml::Linq
using_clr_extensions System::Xml::XPath
require "#{path}/../../Global/terrain/tileObject.rb"
require "#{path}/../../Global/project/project"
require "#{path}/../../Global/perforce/p4utils"
# logging
require "#{path}/../../Global/logging/logging.rb"
#Database
require "#{path}/../../Global/database/DatabaseConnection.rb"
require "#{path}/../../Utils/TerrainTiles/TerrainNotify.rb"
#Terrain_XML_PATH = "#{@g_Config.project.DefaultBranch.Assets}/export/levels/#{@g_Config.project.name}/Terrain/"
GTA_MILO = 'gta_milo'
GTA_MILOTRI = 'gta_milotri'
GTA_MLOROOM = 'gtamloroom'
GTA_REFOBJECT = 'rsrefobject'
GTA_CONTAINER = 'container'
POS_BIAS = 7
TILE_SIZE = 512
SERVER = "nycw-mhb-sql"
# set to True for email notfiy to only author
DEBUG = false
class AnimMissionInfo
attr_reader :mission
attr_reader :animator
attr_reader :animatorEmail
attr_reader :cutsceneList
attr_writer :mission
attr_writer :animator
attr_writer :animatorEmail
attr_writer :cutsceneList
def initialize( _mission, _animator, _animatorEmail )
@mission = _mission
@animator = _animator
@animatorEmail = _animatorEmail
@cutsceneList = []
end
end
class TileInfo
attr_reader :tileID
attr_reader :tileName
attr_reader :cutsceneList
attr_reader :tileBndMin
attr_reader :tileBndMax
attr_writer :tileID
attr_writer :tileName
attr_writer :cutsceneList
def initialize(tileID)
@tileID = tileID
@tileName = ''
@cutsceneList = Hash.new
end
end
class Terrain
attr_reader :terrainList
def initialize(g_Config, g_log)
@@g_Config = g_Config
@@glog = g_log
@terrainList = []
@terrainIDList = []
@@sourceCutsceneDb = "CutsceneStats_#{@@g_Config.project.name.upcase}"
@@sourceAnimDb = "AnimationStats_#{@@g_Config.project.name.upcase}"
@@sourceLevelDB = "LevelStats_#{@@g_Config.project.name.upcase}"
end
# parses teh containers and searches for milo's
def parseXML( xmlfile )
# validate its a terrain file (should end with an _
if ( xmlfile =~ /\/[a-z]_[0-9][0-9]_.xml/im )
@@glog.message("Loading: #{xmlfile}")
begin
@xmldoc = XmlDocument.new
@xmldoc = XDocument::Load( xmlfile )
rescue => e
@@glog.errorEmail(e, "Notify")
@@glog.error("skipping")
return
end
_containerName = ''
_guid = ''
containObj = @xmldoc.Root.XPathSelectElement( 'objects/object' )
if containObj.Attribute( XName::Get( "class" ) ).Value == GTA_CONTAINER then
_containerName = containObj.Attribute( XName::Get( "name" ) ).Value.downcase
_guid = containObj.Attribute( XName::Get( "guid" ) ).Value.downcase
end
@xmldoc.Root.XPathSelectElements( 'objects/object/transform/object/position' ).each {| elm |
_tileObj = TileObject.new()
_tileObj.name = _containerName
_tileObj.guid = _guid
_x = elm.Attribute( XName::Get( "x" ) ).Value.to_i
_y = elm.Attribute( XName::Get( "y" ) ).Value.to_i
_z = elm.Attribute( XName::Get( "z" ) ).Value.to_i
_tileObj.position = [_x, _y, _z]
# sort out X and Y bound
_xMin = _x - (TILE_SIZE / 2)
_yMin = _y - (TILE_SIZE / 2)
_tileObj.boundingBoxMin = [_xMin, _yMin ]
_xMax = _x + (TILE_SIZE / 2)
_yMax = _y + (TILE_SIZE / 2)
_tileObj.boundingBoxMax = [_xMax, _yMax]
@@glog.message(_tileObj.name)
# @@glog.message(_tileObj.guid.to_s)
@@glog.message(_tileObj.position.to_s)
terrainList << _tileObj
}
end
end
def connectDB( srcDB )
@dBconnection.connect(SERVER, srcDB)
end
def closeDB()
@dBconnection.close()
end
# Read in our list of cutscene positions
def parseCutscenes()
@dBconnection = DatabaseConnection.new( @@glog )
#update our list of tiles to the DB
connectDB(@@sourceLevelDB)
terrainList.each do | tile |
@@glog.message("UPDATING #{tile.name}")
paramaters = { '@name' => tile.name,
'@PositionX' => tile.position[0],
'@PositionY' => tile.position[1],
'@PositionZ' => tile.position[2],
'@BndMin' => tile.boundingBoxMin.to_s,
'@BndMax' => tile.boundingBoxMax.to_s
}
table = @dBconnection.read_data('','UpdateTerrainTile', paramaters )
# add our terrain ID to the list so we no what has been updated
@terrainIDList << table[0]['TileID']
end
# Update Cutscene Tile ID's
connectDB(@@sourceCutsceneDb)
paramaters = {}
cutsceneList = @dBconnection.read_data('','GetCutsceneIDPositions', paramaters )
cutsceneList.each do | cutscene |
# check if
terrainList.each do | tile |
if cutscene['vOffset_X'] > tile.boundingBoxMin[0] and cutscene['vOffset_X'] < tile.boundingBoxMax[0] and
cutscene['vOffset_Y'] > tile.boundingBoxMin[1] and cutscene['vOffset_Y'] < tile.boundingBoxMax[1] then
puts "#{cutscene['CutsceneID']} is in tile #{tile.name}"
paramaters = { '@name' => tile.name,
'@cutsceneid' => cutscene['CutsceneID'].to_i
}
@dBconnection.read_data('','UpdateCutsceneTile', paramaters )
end
end
end
# Updated Anim Scene Tile ID's
connectDB(@@sourceAnimDb)
paramaters = {}
cutsceneList = @dBconnection.read_data('','GetAnimIDPositions', paramaters )
cutsceneList.each do | cutscene |
# check if
terrainList.each do | tile |
if cutscene['sceneOrigin_X'] > tile.boundingBoxMin[0] and cutscene['sceneOrigin_X'] < tile.boundingBoxMax[0] and
cutscene['sceneOrigin_Y'] > tile.boundingBoxMin[1] and cutscene['sceneOrigin_Y'] < tile.boundingBoxMax[1] then
puts "#{cutscene['CutsceneID']} is in tile #{tile.name}"
paramaters = { '@name' => tile.name,
'@animid' => cutscene['ID'].to_i
}
@dBconnection.read_data('','UpdateAnimSceneTile', paramaters )
end
end
end
closeDB()
end
def getAffectedCutscenes()
affectedTiles = []
if @terrainIDList.count > 0 then
connectDB(@@sourceCutsceneDb)
@terrainIDList.each do | tileID |
# get a list of affect cutscenes from tile ID if any
paramaters = { '@tileid' => tileID}
table = @dBconnection.read_data('','Automation.GetCutscenesByTileID', paramaters )
if table.count > 0 then
# Create a new Tile HOlder with list of cutscenes
tileInfo = TileInfo.new(tileID)
table.each do | cutscene |
tileInfo.tileName = cutscene['Tile']
if not tileInfo.cutsceneList.include?(cutscene['Mission'])
tileInfo.cutsceneList[cutscene['Mission']] = AnimMissionInfo.new( cutscene['Mission'], cutscene['Animator'], cutscene['Email'] )
end
tileInfo.cutsceneList[cutscene['Mission']].cutsceneList << cutscene['CutsceneName'].to_s
end
affectedTiles << tileInfo
end
end
closeDB()
end
affectedTiles
end
end
# get our change info from a single passed in CL
def parseChangefromCL( cl )
#puts @p4.methods
#f = @p4.get_changelistDescribe( cl )
change = @p4.get_Change_from_CL( cl )
if change != nil
validfiles = @p4.findFilesinChange( change , '*.xml' )
validfiles.each do | xmlfile |
@mapTerrain.parseXML( xmlfile.replace('//', 'x:/' ) )
end
@mapTerrain.parseCutscenes()
affectedTiles = @mapTerrain.getAffectedCutscenes()
if affectedTiles.count > 0 then
userEmail = @p4.get_user_email(change.username)
emailToUsers( affectedTiles, change, userEmail )
end
end
end
if ( __FILE__ == $0 ) then
LogFactory.Initialize()
LogFactory.CreateApplicationConsoleLogTarget( )
g_Log = LogFactory.ApplicationLog
# Config initialisation.
$g_Config = RSG::Base::Configuration::ConfigFactory::CreateConfig( )
@p4 = P4Utils.new(g_Log)
@glog = Logger.new( $g_Config , g_Log)
begin
@mapTerrain = Terrain.new( $g_Config, @glog)
if ARGV.length == 0
@glog.message("Running in Directory mode...")
levelXmlPath = "#{$g_Config.project.DefaultBranch.Export}/levels/rdr3/terrain"
Dir.glob("#{levelXmlPath}/**/*.xml").each do | xmlfile |
@mapTerrain.parseXML( xmlfile )
end
@mapTerrain.parseCutscenes()
elsif ARGV.length > 0
@glog.message("Running in Automation mode...")
cl = ARGV[0].to_i
parseChangefromCL( cl )
end
rescue => e
@glog.errorEmail(e)
raise
end
end