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*') endDrawRE = re.compile(r'\s*') beginSpawnEventRE = re.compile(r'\s*') endSpawnEventRE = re.compile(r'\s*') nameRE = re.compile(r'\s*(([^<\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>(.*)' % (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)