# # # Author:: Mark Harrison-Ball # Date:: 15 September 2013 (AP3) # Purpose: # ~ Inital analyis scene and generate a inital report # - Upload inof to Database # - Run external tool to generate acurate datafrom render # - Generate Bugs from reports #----------------------------------------------------------------------------- # Uses #----------------------------------------------------------------------------- #$LOAD_PATH.unshift File.expand_path('../../Global/perforce/', __FILE__) #NOTES # # Concat names are mission names # Get list of concats # Check name is not a concat name # get clip name from anim name require 'RSG.Base.dll' require 'RSG.Base.Configuration.dll' require 'RSG.Base.Windows.dll' require 'RSG.SourceControl.Perforce' require 'RSG.Metadata' # Core include RSG::Base::Configuration include RSG::Base::Logging include RSG::Base::Logging::Universal include RSG::Base::OS include RSG::SourceControl::Perforce include RSG::Metadata require 'mscorlib' require 'System.Core' require 'System.Xml' include System::Collections::Generic include System::IO include System::Diagnostics include System::Xml include System::Runtime::InteropServices include System::Net include System::Net::Sockets include System::Net::Mail path = File.expand_path $0 path = File.dirname(path) # Tool Specific classes require "#{path}/../../Utils/CutsceneGrader/GradingReader.rb" # global Core classes require "#{path}/../../Global/project/project" require "#{path}/../../Global/perforce/p4utils" require "#{path}/../../Global/email/email.rb" require "/GradingInfo.rb" # To Depreciate as now lives in metautils require "#{path}/../../Global/pargen/pscparser" require "#{path}/../../Global/pargen/pscxmlparser" # require "#{path}/../../Global/metadata/metautils" # Grading Stats require "#{path}/../../Utils/CutsceneGrader/GradingStats" # Cutfile object require "#{path}/../../Global/cutscene/cutInfo" # Clip Parser require "#{path}/../../Global/anim/clip" # Cutscene COntainer require "#{path}/../../Utils/CutsceneGrader/CutsceneDef" # EDL Parser require "#{path}/../../Utils/ESTConversion/ESTconvert" # EXCEL Parser require "#{path}/../../Utils/ESTConversion/TrackingConvert" # Debug Utils require "#{path}/../../Global/debug/debugUtils.rb" # Environment Coords Monitoring require "#{path}/../../Utils/ReadFBX/readFBX.rb" require 'pipeline/os/options' include Pipeline DEBUG = true REPEAT = true # Constants CUTXML = 'data.cutxml' CONCAT = '*.concatlist' # time sleepTime = 60 * 5 def logerror(e = 'unknown') msg = "Exception occured: #{e.message} in #{e.backtrace}" @g_Log.error(msg) #send_email( AUTHOR, EXCEPTION_EMAIL, 'Cutscene Report Tool Crash', msg, @server) end # OLD METHOD def updateStats( cutInfoList ) @g_Log.message('Updating Database Stats') # Get our project we are working with ProjectName = @g_Config.project.name.upcase # Generate our Stats. @cutStats.generateStats( cutInfoList, ProjectName ) end def updateCutStats( objectList ) @g_Log.message('Updating Database Stats') # Get our project we are working with #ProjectName = @g_Config.project.name.upcase # Generate our Stats. #puts objectList @cutStats.generateCutStats( objectList ) end def syncPrequistes() # Sync the definiations files syncPaths = [@g_Config.project.DefaultBranch.Assets + "/metadata/definitions/...", @g_Config.project.DefaultBranch.Assets + "/cuts/...cutxml", @g_Config.project.DefaultBranch.Assets + "/non_final/cutscene/EDL/...edl", @g_Config.project.root + "/docs/Production/*Camera_tracking.xlsm", @g_Config.project.DefaultBranch.Assets + "/cuts/!!Cutlists/...concatlist", @enviromentSets, @g_Config.project.DefaultBranch.Assets + "/cuts/...clip",] # lets see how long this takes (Take 148 seconds from no assets) # Batch up sync commands @p4.sync(syncPaths,'') end def extractMissionName(clip) fbx_property = @clip.getProperty("FBXFile_DO_NOT_RESOURCE",clip) missionName = nil if (fbx_property != nil) then fbx_file = (fbx_property.GetPropertyAttributes()[0]).GetString() fbx_file = fbx_file.Replace('\\','/') assetSplit = fbx_file.Split('/') # get name after "!!scenes" sceneIndex = assetSplit.index("!!scenes") if sceneIndex!=nil missionName = assetSplit[sceneIndex+1] end end missionName end # REFACTOR def getMissionNameFromClips(dir) clip_list = Directory.GetFiles(dir, "*.clip") #puts clip_list # Skip empty folders if(clip_list.Length == 0) then next end puts "==missionName==" missionName = nil #clip_list.each do | clip | for i in (0..clip_list.Length-1) puts "i=#{i.to_s} for clip #{clip_list[i]}" missionName = extractMissionName(clip_list[i]) if missionName != nil then break end end missionName end def getCutInfo(cutFolder) puts "Cutfolder = #{cutFolder}" # To get our mission name we need a fucking clip file clip_list = Directory.GetFiles(cutFolder, "*.clip") # Skip empty folders cutFile = nil if clip_list.Length > 0 puts "==missionName==" missionName = nil #clip_list.each do | clip | for i in (0..clip_list.Length-1) puts "i=#{i.to_s} for clip #{clip_list[i]}" missionName = extractMissionName(clip_list[i]) if missionName != nil then break end end puts 'prcessing cutxml' cutxml = File.join(cutFolder, CUTXML) if File.exist?(cutxml) # Make sure our File Exists cutFile = CutFile.new(cutxml, @metadataUtils) cutFile.missionStrand = missionName debugPrint(cutFile) #debugPrint(cutFile.shots) #puts cutFile.shots[0].models[0].name end end cutFile end # OBSOLETE - REMOVE def processCuts() @g_Log.message("Prcessing Cuts") localList = [] # Process the rest of the cut files projectPath = @g_Config.project.DefaultBranch.Assets + "/cuts/" directory = projectPath DirectoryList = Dir.entries(directory).select { |f| File.directory? File.join(directory, f)} DirectoryList.each do |cutFolder| puts "Procssing #{cutFolder}" if not cutFolder=~/^\.\.?$/ if not cutFolder.start_with?('!!') or not @excludeList.include?(cutFolder.upcase) _cutFile = getCutInfo(File.join(directory,cutFolder)) if _cutFile cutDef = CutsceneDef.new(_cutFile, @ProjectID, P4fileinfo.new()) @CutInfoList.push(cutDef) end end end end localList end # OBSOLETE - REMOVE def processConcuts() # PROCESS OUR CONCATS @g_Log.message("Prcessing Concats") projectPath = @g_Config.project.DefaultBranch.Assets + "/cuts/!!Cutlists/" localList= [] # Get our list of concat files Dir["#{projectPath}*.concatlist"].each do |file| @g_Log.message("Processing #{file}") concatFile = ConcatFile.new(file, @metadataUtils, @g_Log) puts "concatFile = #{concatFile} " #if concatFile.isValid # we need to get the mission name form the first shot if concatFile.shots.count > 0 dirPath = File.dirname(concatFile.shots[0].shotPath) clip_list = Directory.GetFiles(File.join(dirPath), "*.clip") missionName = nil #clip_list.each do | clip | for i in (0..clip_list.Length-1) #puts "i=#{i.to_s} for clip #{clip_list[i]}" missionName = extractMissionName(clip_list[i]) if missionName != nil then break end end concatFile.missionStrand = missionName #File.basename(file,".*") cutDef = CutsceneDef.new(concatFile, @ProjectID, P4fileinfo.new()) @CutInfoList.push(cutDef) @excludeList.push(concatFile.name) debugPrint(concatFile) end end localList end # Make sure email is valid... def validateemail(email) validEmail = email emailTokens = email.split("@") if emailTokens[1] == "take2games.com" then validEmail = emailTokens[0] + "@rockstargames.com" end validEmail end def _getP4HeaderInfo(change, filename) revIndex = @p4.get_file_info(filename, 'headRev') headerinfo = P4fileinfo.new(change) # Update additional p4 Info headerinfo.email = validateemail(@p4.get_user_email(change.username)) headerinfo.filename = filename headerinfo.revision = revIndex.to_i return headerinfo end def fileDepotPath(filename) localPath = nil if filename != nil # FIX FOR GTA in DEPOT PATH :( filename = filename.sub('depot/','') # Switch to X drive localPath = "x:/"+filename.split("//")[1] localPath end end # Check if the data cutxml is in the root of the cutscene # Pass in of a perforce file Path def isRootDataCut(filePath) isValid = false pathSplit = filePath.downcase.split("/") index = pathSplit.index('cuts') if index != nil if pathSplit[index+2] == CUTXML then isValid = true end end return isValid end # MOve to own syncs def parseConcats() # Check for any new Concats @lastCL, changes = @p4.parse_p4_review(@concatsPath, @currentCL, @head) changes.each do | change | validfiles = @p4.findFilesinChange( change, CONCAT ) validfiles.each do | filename | localPath = fileDepotPath(filename) headerinfo = _getP4HeaderInfo(change, filename) _concatFile = ConcatFile.new(localPath, @metadataUtils, @g_Log) puts _concatFile.name if _concatFile.shots.count > 0 dirPath = File.dirname(_concatFile.shots[0].shotPath) clip_list = Directory.GetFiles(File.join(dirPath), "*.clip") missionName = nil #clip_list.each do | clip | for i in (0..clip_list.Length-1) missionName = extractMissionName(clip_list[i]) if missionName != nil then break end end _concatFile.missionStrand = missionName cutDef = CutsceneDef.new(_concatFile, @ProjectID, headerinfo) @CutInfoList.push(cutDef) @excludeList.push(_concatFile.name) end end end end def processTracking() # Check for Tracking DOc Changes @lastCL, changes = @p4.parse_p4_review(@trackingDoc, @currentCL, @head) changes.each do | change | validfiles = nil if @ProjectName == "RDR3" then validfiles = @p4.findFilesinChange( change, 'RDR3_CAMERA_TRACKING.xlsm' ) # Hardcoded xls file elsif @ProjectName == "GTA5" then validfiles = @p4.findFilesinChange( change, 'GTAV_CAMERA_TRACKING.xlsm' ) # Hardcoded xls file end if validfiles.count > 0 then localPath = fileDepotPath(validfiles[0]) if localPath != nil and File.exist?(localPath) then headerinfo = _getP4HeaderInfo(change, validfiles[0]) @ExcelTracking.parseExcelDoc(localPath, headerinfo, @ProjectID ) end end break end end def processEDLs() # Check for EST submits an @lastCL, changes = @p4.parse_p4_review(@edlPath, @currentCL, @head) changes.each do | change | validfiles = @p4.findFilesinChange( change, '*.edl' ) validfiles.each do | filename | localPath = fileDepotPath(filename) if localPath != nil and File.exist?(localPath) then headerinfo = _getP4HeaderInfo(change, filename) @avidUpdate.parseEDL(localPath, headerinfo, @ProjectID ) debugPrint(headerinfo) end end end end # Check for Environment submits def processSets() @lastCL, changes = @p4.parse_p4_review(@enviromentSets, @currentCL, @head) changes.each do | change | validfiles = @p4.findFilesinChange( change, '*.fbx' ) validfiles.each do | filename | localPath = fileDepotPath(filename) if localPath != nil and File.exist?(localPath) then @readFBX.parseFBX(localPath) end end end end def processCuts() @lastCL, changes = @p4.parse_p4_review(@cutsPath, @currentCL, @head) puts @lastCL changes.each do | change | # Check each change, see if there has been a cutxml file submitted validfiles = @p4.findFilesinChange( change, CUTXML ) validfiles.each do | filename | # ignore cutxml files in sub directories. Best to use strict Path if isRootDataCut(filename) then # Set to local Path... prop better way of doign this. # CAn use the rsg source contril file state method but might be a laod on teh p4 server unless its a local command? localPath = fileDepotPath(filename) if localPath != nil and File.exist?(localPath) then if not @excludeList.include?(localPath.upcase) # Get P4 header for CL headerinfo = _getP4HeaderInfo(change, filename) # Get out Cutscene Data _cutFile = getCutInfo(File.dirname(localPath)) if _cutFile cutDef = CutsceneDef.new(_cutFile, @ProjectID, headerinfo) @CutInfoList.push(cutDef) end end end end end end end def parse_p4_review() # List of Cutscene Chnage Inforamtion @excludeList = [] @CutInfoList = [] syncPrequistes() @head = '#head' parseConcats() processCuts() # Upload to Database if @CutInfoList.count > 0 puts @CutInfoList[0] updateCutStats(@CutInfoList) end processEDLs() processTracking() processSets() end # #----------------------------------------------------------------------------- # Entry-Point #----------------------------------------------------------------------------- if ( __FILE__ == $0 ) then #g_Options = OS::Options::new( OPTIONS ) #Need to enable the initlaize on the TOOLS NG Branch LogFactory.Initialize() LogFactory.CreateApplicationConsoleLogTarget( ) @g_Log = LogFactory.ApplicationLog # Config initialisation. @g_Config = RSG::Base::Configuration::ConfigFactory::CreateConfig( ) @email = @g_Config.EmailAddress @server= @g_Config.studios.this_studio.exchange_server @g_Log.message("Using Server: #{@g_Config.studios.this_studio}") # Database/Stat Init @cutStats = GradingStats.new(@g_Log) @avidUpdate = AvidUpdate.new(@g_Log) @ExcelTracking = TrackingDocUpdate.new(@g_Log) @readFBX = ReadFBX.new(@g_Log, @g_Config) branch = @g_Config.Project.DefaultBranch @p4 = P4Utils.new(@g_Log) @clip = Clip.new(@g_Log) # Reference our PSC parser @metadataUtils = MetaData.new( branch ) @gradingreader = GradingReader.new(@g_Log) @ProjectName = @g_Config.project.name.upcase @ProjectID = getProjectID(@ProjectName) # Perforce Monitor PATHS @cutsPath = @g_Config.project.DefaultBranch.Assets + "/cuts/...cutxml" @concatsPath = @g_Config.project.DefaultBranch.Assets + "/cuts/!!Cutlists/...concatlist" @edlPath = @g_Config.project.DefaultBranch.Assets + "/non_final/cutscene/EDL/...edl" @enviromentSets = @g_Config.project.DefaultBranch.Art + "/animation/resources/Sets/...FBX" @trackingDoc = @g_Config.project.root + "/docs/Production/...xlsm" # Get current CL number @currentCL = @p4.get_current_changelistnumber() @currentCL = 5213222 #TEST begin loop do unless not REPEAT begin @g_Log.message('Working in Automation mode') # CHeck the DataBase to see if there is a full grading request #queryGradingRequest() # Check if any new data has been submitted to p4 parse_p4_review() @currentCL = @lastCL @g_Log.message("Current CL: #{@currentCL}") @g_Log.message("Waiting for...#{sleepTime.to_s} seconds.......") sleep(sleepTime) rescue => e logerror(e) end else begin @g_Log.message('Working in Single mode') # Check if we have a grading request #test() @g_Log.message('Complete') rescue => e logerror(e) end break end end end end