Files
gtav-src/tools_ng/script/vfx/dlc_mpTuner_ng/FindPtxDeps.py
T
2025-09-29 00:52:08 +02:00

269 lines
9.8 KiB
Python
Executable File

import sys, os, re, glob, xml.dom.minidom, shutil, stat
from optparse import OptionParser
from sets import *
optparser = OptionParser()
optparser.add_option("", "--excludetex", dest="ExcludeTextureFile")
optparser.add_option("", "--excludemodel", dest="ExcludeModelFile")
optparser.add_option("", "--alwaysincludemodeltex", dest="IncludeModelTex", action="store_true", default=False)
optparser.add_option("", "--override", dest="OverrideDir")
(options, args) = optparser.parse_args()
if len(args) != 1:
optparser.error("Incorrect number of arguments.")
def GetLineSet(filename):
s = Set()
if not filename:
return s
f = file(filename)
for line in f:
l = line.strip()
if len(l) == 0 or l[0] == '#':
continue
s.add(l)
return s
excludeTextures = GetLineSet(options.ExcludeTextureFile)
excludeModels = GetLineSet(options.ExcludeModelFile)
effectRuleList = []
emitRuleList = []
ptxRuleList = []
FxFileName = os.path.abspath(sys.argv[1])
FileDir = os.path.dirname(FxFileName)
Path = os.path.dirname(FileDir)
FileBase = os.path.splitext(os.path.basename(FxFileName))[0]
ModelTextureDirectoryName = "modeltex"
ExitCode = 0
def MakeEmptySetmap():
return {
"textures": Set(),
"shaders": Set(),
"models": Set(),
"emitrules": Set(),
"ptxrules": Set(),
"effectrules": Set(),
"spawnedrules": Set()
}
# procedure:
# Start with initial FxList, find all referenced textures, shaders, models, etc.
# also gather list of effectrules spawned from effect or ptx rules.
# take that list, remove any effects that were in the master fxlist
# repeat until nothing is left in the spawned list.
def FindAllDependencies(originalFxList, override):
masterDependencyList = MakeEmptySetmap()
currfxlist = originalFxList[:]
passNum = 1
while len(currfxlist) > 0:
print "Starting Pass %d" % (passNum)
depList = FindDependencies(currfxlist, override)
for i in ["textures", "shaders", "models", "emitrules", "ptxrules", "effectrules"]:
# add all the new dependencies to the master list
masterDependencyList[i].update(depList[i])
# now find out which of the spawned effects we haven't seen before...
newSpawns = depList["spawnedrules"].difference(masterDependencyList["effectrules"])
print "Finished Pass %d with %d effectrules" % (passNum, len(currfxlist))
currfxlist = [x for x in newSpawns]
passNum += 1
return masterDependencyList
def FindDependencies(fxlist, override):
global ExitCode
depList = MakeEmptySetmap()
for fx in fxlist:
depList["effectrules"].add(fx)
emitRuleList = FindTagValues("effectrules", fx, ".effectrule", "emitterRuleName", override)
depList["emitrules"].update(emitRuleList)
ptxRuleList = FindTagValues("effectrules", fx, ".effectrule", "particleRuleName", override)
depList["ptxrules"].update(ptxRuleList)
spawnedRuleList = FindTagValues("effectrules", fx, ".effectrule", "effectRuleName", override)
depList["spawnedrules"].update(spawnedRuleList)
print " Checking ptxrules"
for ptxrule in depList["ptxrules"]:
textures = FindTagValues("ptxrules", ptxrule, ".ptxrule", "textureName", override)
depList["textures"].update(textures)
shaders = FindTagValues("ptxrules", ptxrule, ".ptxrule", "shaderTemplateName", override)
depList["shaders"].update(shaders)
#drawables are a little harder to find
inDrawables = False
inSpawnEvent = False
beginDrawRE = re.compile(r'\s*<drawables>')
endDrawRE = re.compile(r'\s*</drawables>')
beginSpawnEventRE = re.compile(r'\s*<effectSpawner.+>')
endSpawnEventRE = re.compile(r'\s*</effectSpawner.+>')
nameRE = re.compile(r'\s*<name>(([^<\n])+)')
fileName = os.path.join(Path, "ptxrules", override, ptxrule + ".ptxrule")
if(os.path.exists(fileName)):
print "Found override at", fileName
else:
fileName = os.path.join(Path, "ptxrules", ptxrule + ".ptxrule")
try:
f = file(fileName, "r")
for line in f:
if inDrawables:
match = nameRE.match(line)
if match:
depList["models"].add(match.group(1))
if endDrawRE.match(line):
inDrawables = False
elif inSpawnEvent:
match = nameRE.match(line)
if match:
depList["spawnedrules"].add(match.group(1))
if endSpawnEventRE.match(line):
inSpawnEvent = False
else:
if beginDrawRE.match(line):
inDrawables = True
elif beginSpawnEventRE.match(line):
inSpawnEvent = True
f.close()
except (IOError):
print "Error: Couldn't open file", fileName
ExitCode = 1
print " Found %d emitrules, %d ptxrules, %d spawned effects" % (len(depList["emitrules"]), len(depList["ptxrules"]), len(depList["spawnedrules"]))
return depList
def FindTagValues(folder, fxfile, extn, tag, override):
global Path, ExitCode
found = []
tagRE = re.compile(r'\s*<%s>(.*)</%s>' % (tag,tag))
fileName = os.path.join(Path, folder, override, fxfile + extn)
if(os.path.exists(fileName)):
print "Found override at", fileName
else:
fileName = os.path.join(Path, folder, fxfile + extn)
try:
f = file(fileName, "r")
for line in f:
match = tagRE.match(line)
if match:
data = match.group(1)
if data != "":
found.append(os.path.basename(data))
f.close()
except (IOError):
print "Error: Couldn't open file", fileName
ExitCode = 1
return found
def writeSet(s, extn):
global FileDir, FileBase, ExitCode
sortlist = [x for x in s]
sortlist.sort()
fileName = os.path.join(FileDir, FileBase + "/" + FileBase + "." + extn)
try:
file(fileName, "w").write("\n".join(sortlist))
except (IOError):
print "Error: Couldn't open file", fileName, "for writing"
ExitCode = 1
###########################################################
###########################################################
###########################################################
try:
mainFile = file(FxFileName, "r")
except (IOError):
print "Error: Couldn't open fxlist file", FxFileName
sys.exit(1)
initialFxList = []
for i in mainFile:
fxName = i.strip()
if len(fxName) == 0 or fxName[0] == '#':
continue
initialFxList.append(fxName)
depList = FindAllDependencies(initialFxList, options.OverrideDir)
# remove any models that are in the exclude lists
depList["models"] -= excludeModels
# remove any textures that are in the exclude lists
depList["textures"] -= excludeTextures
# now add all the textures referenced by the models in the modellist to the texlist (copy them to the modeltex folder too)
try:
os.makedirs(os.path.join(Path, ModelTextureDirectoryName))
except OSError:
pass
for modelName in depList["models"]:
modelDirPart = os.path.split(modelName.strip())[0]
modelDir = os.path.join(Path, "models", modelDirPart)
svaList = glob.glob(os.path.join(modelDir, "*.sva"))
svaList += glob.glob(os.path.join(modelDir, "*.type"))
for svaFileName in svaList:
svaFile = None
try:
svaFile = file(svaFileName, "r")
except (IOError):
print "Error: Couldn't open file", svaFileName
ExitCode = 1
continue
for svaLine in svaFile:
toks = svaLine.strip().split()
if len(toks) == 2 and toks[0] == "grcTexture":
rawTextureName = toks[1]
textureName = os.path.splitext(rawTextureName)[0]
srcTextureName = os.path.join(modelDir, textureName + ".dds")
dstTextureName = os.path.join(Path, ModelTextureDirectoryName, textureName + ".dds")
if os.path.exists(dstTextureName) and os.path.getmtime(srcTextureName) != os.path.getmtime(dstTextureName):
print "overwriting %s with %s" % (dstTextureName, srcTextureName)
try:
os.chmod(dstTextureName, stat.S_IWRITE)
shutil.copy2(srcTextureName, dstTextureName)
except:
print "Error: Failed to overwrite %s" % (dstTextureName)
elif not os.path.exists(dstTextureName):
print "copying to %s from %s" % (dstTextureName, srcTextureName)
try:
shutil.copy2(srcTextureName, dstTextureName)
except:
print "Error: Failed to copy %s to %s" % (srcTextureName, dstTextureName)
depList["textures"].add(rawTextureName)
svaFile.close()
if not options.IncludeModelTex:
# remove any of the newly added model textures that are in the exclude lists
depList["textures"] -= excludeTextures
try:
os.makedirs(os.path.join(FileDir, FileBase))
except OSError:
pass
# finally write all the lists
writeSet(initialFxList, "fxlist")
writeSet(depList["effectrules"], "effectlist")
writeSet(depList["emitrules"], "emitlist")
writeSet(depList["ptxrules"], "ptxlist")
writeSet(depList["models"], "modellist")
writeSet(depList["textures"], "texlist")
#writeSet(depList["shaders"], "shaderlist")
sys.exit(ExitCode)