import sys, os, re, glob, xml.dom.minidom, shutil, stat, hashlib from optparse import OptionParser from sets import * usage = "usage: %prog in.fxlist [c:/outputpath/]" optparser = OptionParser(usage=usage) optparser.add_option("", "--excludetex", dest="ExcludeTextureFile") optparser.add_option("", "--excludemodel", dest="ExcludeModelFile") (options, args) = optparser.parse_args() if ((len(args) != 1) and (len(args) != 2)): 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.lower()) 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] if (len(args) == 1): OutputFileDir = os.path.join(FileDir, FileBase) if (len(args) == 2): OutputFileDir = os.path.abspath(sys.argv[2]) ModelTextureDirectoryName = "modeltex" ExitCode = 0 ChecksumString = "" 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): masterDependencyList = MakeEmptySetmap() currfxlist = originalFxList[:] passNum = 1 while len(currfxlist) > 0: print "Starting Pass %d" % (passNum) depList = FindDependencies(currfxlist) 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): global ExitCode depList = MakeEmptySetmap() for fx in fxlist: depList["effectrules"].add(fx.lower()) emitRuleList = FindTagValues("effectrules", fx, ".effectrule", "EmitRuleName") depList["emitrules"].update(emitRuleList) ptxRuleList = FindTagValues("effectrules", fx, ".effectrule", "PtxRuleName") depList["ptxrules"].update(ptxRuleList) spawnedRuleList = FindTagValues("effectrules", fx, ".effectrule", "EffectName") depList["spawnedrules"].update(spawnedRuleList) print " Checking ptxrules" for ptxrule in depList["ptxrules"]: textures = FindTagValues("ptxrules", ptxrule, ".ptxrule", "TextureName") depList["textures"].update(textures) shaders = FindTagValues("ptxrules", ptxrule, ".ptxrule", "ShaderName") depList["shaders"].update(shaders) #drawables are a little harder to find inDrawables = False inSpawnEffect = False beginDrawRE = re.compile(r'\s*') endDrawRE = re.compile(r'\s*') beginSpawnEffectRE = re.compile(r'\s*') endSpawnEffectRE = re.compile(r'\s*') nameRE = re.compile(r'\s*(([^<\n])+)') 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).lower()) if endDrawRE.match(line): inDrawables = False elif inSpawnEffect: match = nameRE.match(line) if match: depList["spawnedrules"].add(match.group(1).lower()) if endSpawnEffectRE.match(line): inSpawnEffect = False else: if beginDrawRE.match(line): inDrawables = True elif beginSpawnEffectRE.match(line): inSpawnEffect = 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): global Path, ExitCode found = [] tagRE = re.compile(r'\s*<%s>(.*)' % (tag,tag)) 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) found.append(os.path.basename(data).lower()) f.close() except (IOError): print "Error: Couldn't open file", fileName ExitCode = 1 return found def writeSet(s, extn, baseDir, baseExtn): global FileDir, FileBase, ExitCode, OutputFileDir, ChecksumString, Path sortlist = [x for x in s] sortlist.sort() fileName = os.path.join(OutputFileDir, FileBase + "." + extn) try: file(fileName, "w").write("\n".join(sortlist)) except (IOError): print "Error: Couldn't open file", fileName, "for writing" ExitCode = 1 if baseDir: # build up our checksum string here for filename in sortlist: ChecksumString += "%s/%s\t%s\n" % (baseDir, filename, os.path.getmtime(os.path.join(Path, baseDir, filename + "." + baseExtn))) ########################################################### ########################################################### ########################################################### 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) # remove any models that are in the exclude lists depList["models"] -= excludeModels # 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.lower()) svaFile.close() # remove any textures that are in the exclude lists depList["textures"] -= excludeTextures try: os.makedirs(OutputFileDir) except OSError: pass # finally write all the lists writeSet(depList["textures"], "texlist", "textures", "dds") writeSet(depList["shaders"], "shaderlist", None, None) writeSet(depList["models"], "modellist", "models", "type") writeSet(depList["emitrules"], "emitlist", "emitrules", "emitrule") writeSet(depList["ptxrules"], "ptxlist", "ptxrules", "ptxrule") writeSet(depList["effectrules"], "fullfxlist", "effectrules", "effectrule") writeSet(initialFxList, "fxlist", None, None) hash = hashlib.md5(ChecksumString).hexdigest() checksumFile = file(os.path.join(OutputFileDir, "checksum.txt"), "w").write(hash) # finally finally generate a checksum sys.exit(ExitCode)