163 lines
7.1 KiB
Python
Executable File
163 lines
7.1 KiB
Python
Executable File
import os
|
|
import copy
|
|
from subprocess import Popen, PIPE
|
|
from xml.etree import ElementTree as ET
|
|
from xml.dom import minidom
|
|
|
|
import pyfbsdk as mobu
|
|
import RS.Perforce as P4
|
|
|
|
|
|
def RunTerminalCommand(cmdTxt):
|
|
process = Popen(cmdTxt, shell=True, stdout=PIPE)
|
|
output = process.communicate()[0]
|
|
return output
|
|
|
|
|
|
def WriteCleanXml(rootNode, xmlPath):
|
|
outputString = ET.tostring(rootNode, encoding="utf-8")
|
|
xmlDoc = minidom.parseString(outputString)
|
|
prettyXml = '\n'.join([line for line in xmlDoc.toprettyxml(indent=' '*2, encoding='utf-8').split('\n') if line.strip()])
|
|
with open(xmlPath, "wb") as fileHandle:
|
|
fileHandle.write(prettyXml)
|
|
|
|
|
|
def SetupGameContent(changeListNumber=None):
|
|
# Get Project Root and Name
|
|
projectRoot = mobu.FBApplication().FBXFileName.split("{0}art{0}".format(os.path.sep))[0]
|
|
projectName = projectRoot.split(os.path.sep)[1].upper()
|
|
|
|
# Get Mission Name
|
|
fbxName = os.path.split(mobu.FBApplication().FBXFileName)[1][:-4].upper()
|
|
missionText = fbxName.split("_")[0].lower()
|
|
if projectName == "GTA5_DLC":
|
|
missionText = "_".join(fbxName.split("_")[:2]).lower()
|
|
|
|
# Create List of Xml Paths
|
|
xmlList = []
|
|
if projectName == "RDR3":
|
|
xmlList.append(os.path.join(projectRoot, "build", "dev", "common", "data", "common_cutscene.meta"))
|
|
xmlList.append(os.path.join(projectRoot, "build", "dev", "common", "data", "anim", "anim.meta"))
|
|
if projectName == "GTA5_DLC":
|
|
xmlList.append(os.path.join(projectRoot, "build", "dev_ng", "content.xml"))
|
|
|
|
# Loop Through Each Xml Path - and set search text
|
|
for xmlPath in xmlList:
|
|
searchText = "/anim/animscenes/cuts@" if xmlPath.endswith("anim.meta") else "/anim/cutscene/cuts_"
|
|
|
|
# Sync Latest Xml, rootNode, and dataFilesNode
|
|
P4.Sync(xmlPath, force=True)
|
|
tree = ET.parse(xmlPath)
|
|
rootNode = tree.getroot()
|
|
if rootNode.tag == "dataFiles":
|
|
dataFilesNode = rootNode
|
|
else:
|
|
dataFilesNode = tree.find("dataFiles")
|
|
|
|
# Search For Cutscene RPFs for Matching Nodes
|
|
rpfNodes = [node for node in dataFilesNode.findall(".//Item/filename/..") if searchText in node.find("filename").text.lower()]
|
|
matchedNode = [node for node in rpfNodes if node.find("filename").text.lower().endswith("{0}{1}.rpf".format(searchText, missionText))]
|
|
|
|
# Scene RPF Not Found - copy and add a new node
|
|
if rpfNodes and matchedNode == []:
|
|
platformText = rpfNodes[0].find("filename").text.lower().split(searchText)[0]
|
|
rpfText = "{0}{1}{2}.rpf".format(platformText, searchText, missionText)
|
|
|
|
newNode = copy.deepcopy(rpfNodes[0])
|
|
filenameNode = newNode.find("filename")
|
|
filenameNode.text = rpfText
|
|
dataFilesNode.append(newNode)
|
|
|
|
# RDR Specific - Sort And Cleanup Nodes
|
|
if projectName == "RDR3":
|
|
# Sort And Cleanup Nodes
|
|
container = dataFilesNode
|
|
data = []
|
|
keyList = []
|
|
for elem in container:
|
|
nameNode = elem.find("filename")
|
|
key = nameNode.text.lower()
|
|
nameNode.text = key
|
|
if key not in keyList:
|
|
keyList.append(key)
|
|
data.append((key, elem))
|
|
data.sort()
|
|
container[:] = [item[-1] for item in data]
|
|
|
|
# GTA5 DLC Specific - Add extra fileToEnable node
|
|
else:
|
|
dlcPackName = rpfText.split("dlc_")[1].split(":")[0].upper()
|
|
changeSetText = "{}_AUTOGEN".format(dlcPackName)
|
|
enableFilesNode = rootNode.find(".//*[changeSetName='{}']/filesToEnable".format(changeSetText))
|
|
if enableFilesNode != []:
|
|
itemNodes = [node for node in enableFilesNode.findall("Item") if "/anim/cutscene/cuts_" in node.text]
|
|
matchedNode = [node for node in enableFilesNode.findall("Item") if node.text.lower() == rpfText.lower()]
|
|
if rpfNodes and matchedNode == []:
|
|
newNode = copy.deepcopy(itemNodes[0])
|
|
newNode.text = rpfText
|
|
enableFilesNode.append(newNode)
|
|
|
|
# Write Out Updated Xml - and add to changelist if provided
|
|
P4.Edit(xmlPath)
|
|
# tree.write(xmlPath, encoding="UTF-8")
|
|
WriteCleanXml(rootNode, xmlPath)
|
|
if changeListNumber:
|
|
os.chdir(projectRoot)
|
|
cmdTxt = "p4 reopen -c {0} {1}".format(changeListNumber, xmlPath)
|
|
RunTerminalCommand(cmdTxt)
|
|
|
|
|
|
def SetupToolsContent(changeListNumber=None):
|
|
# Get Project Paths and Name
|
|
projectRoot = os.environ.get("RS_PROJROOT")
|
|
toolsRoot = os.environ.get("RS_TOOLSROOT")
|
|
assetRoot = os.path.join(projectRoot, "assets")
|
|
projectName = os.path.basename(projectRoot).upper()
|
|
|
|
# Get Content Files
|
|
if projectName == "RDR3":
|
|
contentFiles = [os.path.join(toolsRoot, "etc", "content", "content_animation_cutscene.xml"),
|
|
os.path.join(toolsRoot, "etc", "content", "content_animation_cutscene_fbx.xml")]
|
|
contentToolPath = os.path.join(assetRoot, "metadata", "content", "generator", "GenerateCutsceneContent.bat")
|
|
cmdTxt = "{} < nul".format(contentToolPath)
|
|
elif projectName == "GTA5_DLC":
|
|
contentFiles = [os.path.join(projectRoot, "content_animation_cutscene.xml"),
|
|
os.path.join(projectRoot, "content_animation_cutscene_fbx.xml")]
|
|
contentToolPath = os.path.join(toolsRoot, "bin", "Cutscene", "content", "cutscene_content_generator.exe")
|
|
cmdTxt = "{0} --fbx --target={1}".format(contentToolPath, projectRoot.split(os.path.sep)[-1])
|
|
else:
|
|
errorMsg = "Error: This FBX is from a project the content update tool doesn't support."
|
|
print errorMsg
|
|
return errorMsg
|
|
|
|
# Sync Latest Content Xml Files
|
|
P4.Revert(contentFiles)
|
|
P4.Sync(contentFiles, force=True)
|
|
|
|
# Run Content Tool Command
|
|
os.chdir(projectRoot)
|
|
RunTerminalCommand(cmdTxt)
|
|
|
|
# Move Files to Our ChangeList - if they were updated
|
|
for eachXml in contentFiles:
|
|
eachP4Obj = P4.GetFileState(eachXml)
|
|
if P4.IsOpenForEdit(eachP4Obj):
|
|
cmdTxt = "p4 diff -ds {}".format(eachXml)
|
|
output = RunTerminalCommand(cmdTxt)
|
|
diffText = output.split("====\r")[1]
|
|
# File Identical - we revert it
|
|
if len(diffText) < 5:
|
|
P4.Revert(eachXml)
|
|
# File Updated and ChangeList Provided - move to our changelist
|
|
elif changeListNumber:
|
|
cmdTxt = "p4 reopen -c {0} {1}".format(changeListNumber, eachXml)
|
|
RunTerminalCommand(cmdTxt)
|
|
|
|
|
|
def Run():
|
|
fbxPath = mobu.FBApplication().FBXFileName.lower()
|
|
animationFolder = "{0}art{0}animation{0}".format(os.path.sep)
|
|
if animationFolder in fbxPath and os.path.splitext(fbxPath)[1] == ".fbx":
|
|
SetupGameContent()
|
|
SetupToolsContent()
|