Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ########### VALVE FILESYSTEM INTEGRATION ###########
- from path import Path, PathError
- import os
- import sys
- ### Platform
- WIN_32_SUFFIX = 'win32'
- WIN_64_SUFFIX = 'win64'
- #make sure there is a HOME var...
- try:
- os.environ['HOME'] = os.environ['USERPROFILE']
- except KeyError:
- os.environ['HOME'] = str( Path( '%HOMEDRIVE%/%HOMEPATH%' ) )
- _MOD = None
- def mod():
- '''
- returns the mod name of the current project
- '''
- global _MOD
- try:
- _MOD = Path( os.environ[ 'VPROJECT' ] ).name()
- return _MOD
- except KeyError:
- raise KeyError( '%VPROJECT% not defined' )
- _GAME = None
- def game():
- '''
- returns a Path instance representing the %VGAME% path - path construction this way is super easy:
- somePropPath = game() / mod() / 'models/props/some_prop.dmx'
- '''
- global _GAME
- try:
- _GAME = Path.Join( os.environ[ 'VPROJECT' ], '..' )
- return _GAME
- except KeyError:
- raise KeyError( '%VPROJECT% not defined.' )
- except PathError:
- raise PathError( '%VPROJECT% is defined with an invalid path.' )
- _CONTENT = None
- def content():
- '''
- returns a Path instance representing the %VCONTENT% path - path construction this way is super easy:
- somePropPath = content() / 'ep3/models/characters/alyx/maya/alyx_model.ma'
- '''
- global _CONTENT
- try:
- return Path( os.environ[ 'VCONTENT' ] )
- except KeyError:
- try:
- _CONTENT = Path.Join( os.environ[ 'VPROJECT' ], '../../content' )
- return _CONTENT
- except KeyError:
- KeyError( '%VPROJECT% not defined' )
- _PROJECT = None
- def project():
- '''
- returns a Path instance representing the %VPROJECT% path - path construction this way is super easy:
- somePropPath = project() / 'models/props/some_prop.mdl'
- '''
- global _PROJECT
- try:
- _PROJECT = Path( os.environ[ 'VPROJECT' ] )
- return _PROJECT
- except KeyError:
- raise KeyError( '%VPROJECT% not defined' )
- _TOOLS = None
- def tools( engine='Source 2' ):
- '''
- returns the location of our tools.
- '''
- global _TOOLS
- if engine == 'Source':
- if _TOOLS is None:
- try:
- _TOOLS = Path(os.environ['VTOOLS'])
- except KeyError:
- try:
- _TOOLS = Path.Join( os.environ[ 'VGAME' ], '/../../tools' )
- except KeyError:
- try:
- _TOOLS = Path.Join( os.environ[ 'VPROJECT' ], '/../../../tools' )
- except KeyError:
- raise KeyError('%VGAME% or %VPROJECT% not defined - cannot determine tools path')
- else:
- if _TOOLS is None:
- try:
- _TOOLS = Path(os.environ['VTOOLS'])
- except KeyError:
- try:
- _TOOLS = Path.Join( os.environ[ 'VGAME' ], '/sdktools' )
- except KeyError:
- try:
- _TOOLS = Path.Join( os.environ[ 'VPROJECT' ], '../sdktools' )
- except KeyError:
- raise KeyError('%VGAME% or %VPROJECT% not defined - cannot determine tools path')
- return _TOOLS
- _PLATFORM = WIN_32_SUFFIX
- def platform():
- '''
- Returns the platform of the current environment, defaults to win32
- '''
- global _PLATFORM
- try:
- _PLATFORM = os.environ[ 'VPLATFORM' ]
- except KeyError:
- try:
- # next try to determine platform by looking for win64 bin directory in the path
- bin64Dir = r'{0}\bin\{1}'.format( os.environ['VGAME'], WIN_64_SUFFIX )
- if bin64Dir in os.environ['PATH']:
- _PLATFORM = WIN_64_SUFFIX
- except ( KeyError, PathError ):
- pass
- return _PLATFORM
- def iterContentDirectories():
- for m in gameInfo.getSearchMods():
- yield content() / m
- def iterGameDirectories():
- for m in gameInfo.getSearchMods():
- yield game() / m
- def resolveValvePath( valvePath, basePath=content() ):
- '''
- A "Valve Path" is one that is relative to a mod - in either the game or content tree.
- Ie: if you have a project with the content dir: d:/content and the game dir: d:/game
- a "Valve Path" looks like this: models/awesomeProps/coolThing.vmdl
- To resolve this path one must look under each mod the current project inherits from.
- So a project "test" which inherits from "another" would result in the following searches:
- d:/content/test/models/awesomeProps/coolThing.vmdl
- d:/content/another/models/awesomeProps/coolThing.vmdl
- Similarly for the game tree.
- If the path cannot be resolved to a real file, None is returned.
- '''
- for mod in gameInfo.getSearchMods():
- p = basePath / mod / valvePath
- if p.exists:
- return p
- def setMod( newMod ):
- '''
- sets the current mod to something else. makes sure to update VPROJECT, VMOD and re-parses global gameInfo for
- the new mod so that calls to gamePath and contentPath return correctly
- '''
- global gameInfo
- os.environ[ 'VMOD' ] = str( newMod )
- os.environ[ 'VPROJECT' ] = (game() / newMod).asNative()
- gameInfo = GameInfoFile()
- def reportUsageToAuthor( author=None, payloadCB=None ):
- '''
- when called, this method will fire of a useage report email to whoever has marked themselves as the __author__ of the tool
- the call was made from. if no author is found then an email is sent to the DEFAULT_AUTHOR
- '''
- #additionalMsg = ''
- #try:
- #additionalMsg = payloadCB()
- #except: pass
- #try:
- #fr = inspect.currentframe()
- #frameInfos = inspect.getouterframes( fr, 0 )
- #dataToSend = []
- #if author is None:
- ##set the default - in case we can't find an __author__ variable up the tree...
- #author = DEFAULT_AUTHOR
- ##in this case, walk up the caller tree and find the top most __author__ variable definition
- #for frameInfo in frameInfos:
- #frame = frameInfo[0]
- #dataToSend.append( '%s: %s' % (Path( frameInfo[1] ) - '%VTOOLS%', frameInfo[3]) )
- #if author is None:
- #try:
- #author = frame.f_globals['__author__']
- #except KeyError: pass
- #try:
- #author = frame.f_locals['__author__']
- #except KeyError: pass
- #import smtplib
- #envDump = '\ncontent: %s\nproject: %s\n' % (content(), project())
- #subject = '[using] %s' % str( Path( frameInfos[1][1] ).name() )
- #msg = u'Subject: %s\n\n%s\n\n%s\n\n%s' % (subject, '\n'.join( map(str, dataToSend) ), envDump, additionalMsg)
- #def sendMail():
- #try:
- #svr = smtplib.SMTP( MAIL_SERVER )
- #svr.sendmail( '%s@valvesoftware.com' % os.environ[ 'USERNAME' ], author, msg )
- #except: pass
- ##throw the mail sending into a separate thread in case the mail server is being tardy - if it succeeds, great, if something happens, meh...
- #threading.Thread( target=sendMail ).start()
- ##NOTE: this method should never ever throw an exception... its purely a useage tracking tool and if it fails, it should fail invisibly...
- #except: pass
- pass
- def asRelative( path ):
- '''
- '''
- return str( Path(path).asRelative() )
- def contentModRelativePath( path ):
- '''
- returns a path instance that is relative to the mod if the path is under the content tree
- '''
- return (path - content())[1:]
- def projectRelativePath( path ):
- '''
- returns a path instance that is relative to vproject(). this method is provided purely for symmetry - its pretty trivial
- '''
- return path - project()
- def makeSourceAbsolutePath( filepath ):
- '''
- Returns a Path instance as a "source" absolute filepath.
- If the filepath doesn't exist under the project tree, the original filepath is returned.
- '''
- if filepath.isUnder( content() ):
- relative = filepath - content()
- elif filepath.isUnder( game() ):
- relative = filepath - game()
- else:
- return filepath
- relToCurMod = relative[ 1: ]
- return relToCurMod
- def makeSource1TexturePath( thePath ):
- '''
- returns the path as if it were a source1 texture/material path - ie the path is relative to the
- materials, or materialsrc directory. if the materials or materialsrc directory can't be found
- in the path, the original path is returned
- '''
- if not isinstance( thePath, Path ):
- thePath = Path( thePath )
- try:
- idx = thePath.index( 'materials' )
- except ValueError:
- try:
- idx = thePath.index( 'materialsrc' )
- except ValueError:
- return thePath
- return thePath[ idx+1: ]
- ########### DEPENDENCY CHECKING ###########
- _VALIDATE_LOCATION_IMPORT_HOOK = None
- def EnableValidDependencyCheck():
- '''
- sets up an import hook that ensures all imported modules live under the game directory
- '''
- global _VALIDATE_LOCATION_IMPORT_HOOK
- validPaths = [ game() ]
- class Importer(object):
- def find_module( self, fullname, path=None ):
- lastName = fullname.rsplit( '.', 1 )[ -1 ]
- scriptName = lastName +'.py'
- if path is None:
- path = []
- #not sure if there is a better way of asking python where it would look for a script/module - but I think this encapsulates the logic...
- #at least under 2.6. I think > 3 works differently?
- for d in (path + sys.path):
- pyFilepath = Path( d ) / scriptName
- pyModulePath = Path( d ) / lastName / '__init__.py'
- if pyFilepath.exists or pyModulePath.exists:
- for validPath in validPaths:
- if pyFilepath.isUnder( validPath ):
- return None
- print "### importing a script outside of game!", pyFilepath
- return None
- return None
- _VALIDATE_LOCATION_IMPORT_HOOK = Importer()
- sys.meta_path.append( _VALIDATE_LOCATION_IMPORT_HOOK )
- def DisableValidDependencyCheck():
- '''
- disables the location validation import hook
- '''
- global _VALIDATE_LOCATION_IMPORT_HOOK
- if _VALIDATE_LOCATION_IMPORT_HOOK is None:
- return
- sys.meta_path.remove( _VALIDATE_LOCATION_IMPORT_HOOK )
- _VALIDATE_LOCATION_IMPORT_HOOK = None
- try:
- enableHook = os.environ[ 'ENSURE_PYTHON_CONTAINED' ]
- if enableHook: EnableValidDependencyCheck()
- except KeyError:
- pass
- ########### VALVE SPECIFIC PATH METHODS ###########
- def expandAsGame( self, gameInfo, extension=None ):
- '''
- expands a given "mod" relative path to a real path under the game tree. if an extension is not given, it is
- assumed the path already contains an extension. ie: models/player/scout.vmt would get expanded to:
- <gameRoot>/<mod found under>/models/player/scout.vmt - where the mod found under is the actual mod the file
- exists under on the user's system
- '''
- thePath = self
- if extension is not None:
- thePath = self.setExtension( extension )
- searchPaths = gameInfo.getSearchPaths()
- for path in searchPaths:
- tmp = path / thePath
- if tmp.exists:
- return tmp
- return None
- def expandAsContent( self, gameInfo, extension=None ):
- '''
- as for expandAsGame except for content rooted paths
- '''
- thePath = self
- if extension is not None:
- thePath = self.setExtension( extension )
- searchMods = gameInfo.getSearchMods()
- for mod in searchMods:
- underMod = '%VCONTENT%' / (mod / thePath)
- if underMod.exists:
- return underMod
- return None
- def belongsToContent( self, gameInfo ):
- for mod in gameInfo.getSearchMods():
- if self.isUnder( content() / mod ):
- return True
- return False
- def belongsToGame( self, gameInfo ):
- for mod in gameInfo.getSearchMods():
- if self.isUnder( game() / mod ):
- return True
- return False
- def asRelative( self ):
- '''
- returns the path relative to either VCONTENT or VGAME. if the path isn't under either of these directories
- None is returned
- '''
- c = content()
- g = game()
- if self.isUnder( c ):
- return self - c
- elif self.isUnder( g ):
- return self - g
- return None
- Path.expandAsGame = expandAsGame
- Path.expandAsContent = expandAsContent
- Path.belongsToContent = belongsToContent
- Path.belongsToGame = belongsToGame
- Path.asRelative = asRelative
- ########### VALVE KEYVALUES PARSER ###########
- def removeLineComments( lines ):
- '''
- removes all line comments from a list of lines
- '''
- newLines = []
- for line in lines:
- commentStart = line.find('//')
- if commentStart != -1:
- line = line[:commentStart]
- if not line: continue
- # strip trailing whitespace and tabs
- line = line.rstrip( ' \t' )
- newLines.append(line)
- return newLines
- def removeBlockComments( lines ):
- '''
- removes all block comments from a list of lines
- '''
- newLines = []
- end = len(lines)
- n = 0
- while n<end:
- blockCommentStart = lines[n].find('/*')
- newLines.append(lines[n])
- contFlag = 0
- if blockCommentStart != -1:
- newLines[-1] = lines[n][:blockCommentStart]
- while n<end:
- blockCommentEnd = lines[n].find('*/')
- if blockCommentEnd != -1:
- newLines[-1] += lines[n][blockCommentEnd+2:]
- n+=1
- contFlag = 1
- break
- n+=1
- if contFlag: continue
- n+=1
- return newLines
- class Chunk( object ):
- '''
- a chunk creates a reasonably convenient way to hold and access key value pairs, as well as a way to access
- a chunk's parent. the value attribute can contain either a string or a list containing other Chunk instances
- '''
- def __init__( self, key, value=None, parent=None, append=False, quoteCompoundKeys=True ):
- self.key = key
- self.value = value
- self.parent = parent
- self.quoteCompoundKeys = quoteCompoundKeys
- if append:
- parent.append(self)
- def __getitem__( self, item ):
- return self.value[item]
- def __getattr__( self, attr ):
- if self.hasLen:
- for val in self.value:
- if val.key == attr:
- return val
- raise AttributeError( "has no attribute called %s"%attr )
- def __len__( self ):
- if self.hasLen: return len(self.value)
- return None
- def _hasLen( self ):
- return isinstance( self.value, list )
- hasLen = property(_hasLen)
- def __iter__( self ):
- if self.hasLen:
- return iter(self.value)
- raise TypeError( "non-compound value is not iterable" )
- def __repr__( self, depth=0 ):
- strLines = []
- compoundLine = '{0}{1}\n'
- if self.quoteCompoundKeys:
- compoundLine = '{0}"{1}"\n'
- if isinstance( self.value,list ):
- strLines.append( compoundLine.format( '\t'*depth, self.key ) )
- strLines.append( '\t'*depth +'{\n' )
- for val in self.value: strLines.append( val.__repr__( depth+1 ) )
- strLines.append( '\t'*depth +'}\n' )
- else:
- v = self.value
- strLines.append( '%s"%s" "%s"\n'%('\t'*depth, self.key, v) )
- return ''.join( strLines )
- __str__ = __repr__
- def __hash__( self ):
- return id( self )
- def iterChildren( self ):
- '''
- '''
- if self.hasLen:
- for chunk in self:
- if chunk.hasLen:
- for subChunk in chunk.iterChildren():
- yield subChunk
- else:
- yield chunk
- def asDict( self, parentDict ):
- if isinstance(self.value, list):
- parentDict[self.key] = subDict = {}
- for c in self.value:
- c.asDict(subDict)
- else:
- parentDict[self.key] = self.value
- def append( self, new ):
- '''
- Append a chunk to the end of the list.
- '''
- if not isinstance( self.value, list ):
- self.value = []
- self.value.append( new )
- #set the parent of the new Chunk to this instance
- new.parent = self
- def insert( self, index, new ):
- '''
- Insert a new chunk at a particular index.
- '''
- if not isinstance( self.value, list ):
- self.value = []
- self.value.insert( index, new )
- # Set the parent of the new Chunk to this instance
- new.parent = self
- def findKey( self, key ):
- '''
- recursively searches this chunk and its children and returns a list of chunks with the given key
- '''
- matches = []
- if self.key == key:
- matches.append(self)
- if self.hasLen:
- for val in self.value:
- matches.extend(val.findKey(key))
- return matches
- def findValue( self, value ):
- '''
- recursively searches this chunk and its children and returns a list of chunks with the given value
- '''
- matches = []
- if self.hasLen:
- for val in self.value:
- matches.extend(val.findValue(value))
- elif self.value == value:
- matches.append(self)
- return matches
- def findKeyValue( self, key, value ):
- '''
- recursively searches this chunk and its children and returns a list of chunks with the given key AND value
- '''
- matches = []
- if self.hasLen:
- for val in self.value:
- matches.extend(val.findKeyValue(key,value))
- elif self.key == key and self.value == value:
- matches.append(self)
- return matches
- def testOnValues( self, valueTest ):
- matches = []
- if self.hasLen:
- for val in self.value:
- matches.extend( val.testOnValues(valueTest) )
- elif valueTest(self.value):
- matches.append(self)
- return matches
- def listAttr( self ):
- #lists all the "attributes" - an attribute is just as a named key. NOTE: only Chunks with length have attributes
- attrs = []
- for attr in self:
- attrs.append(attr.key)
- return attrs
- def hasAttr( self, attr ):
- attrs = self.listAttr()
- return attr in attrs
- def getFileObject( self ):
- '''
- walks up the chunk hierarchy to find the file to which this chunk instance belongs
- '''
- parent = self.parent
- lastParent = parent
- safety = 1000
- while parent is not None and safety:
- lastParent = parent
- parent = parent.parent
- safety -= 1
- return lastParent
- def parseLine( line ):
- '''
- this line parser works well for all internal key value files I've thrown at it
- '''
- c = line.count('"')
- if c == 4:
- toks = line[1:-1].split('"')
- return toks[0],toks[-1]
- if c == 2:
- #so this could mean we have a
- #A) "key" value OR
- #B) key "value" OR
- #C) "key"
- if line.strip().startswith('"'):
- toks = [tok.strip() for tok in line[1:].split('"')]
- tokCount = len(toks)
- if tokCount == 2:
- return toks[0],toks[-1].strip()
- elif tokCount == 1:
- return toks[0],[]
- else:
- toks = [tok.strip() for tok in line.rstrip()[:-1].split('"')]
- #toks = line.split()
- #idx = line.find('"')
- #value = line[idx:].strip()[1:-1]
- tokCount = len(toks)
- if tokCount == 2:
- return toks[0],toks[-1].strip()
- elif tokCount == 1:
- return toks[0],[]
- elif tokCount > 2:
- key = toks[0]
- for v in toks[1:]:
- if v.strip() != '':
- return key, v
- if c == 0:
- toks = line.split()
- tokCount = len(toks)
- if tokCount == 2: return toks[0],toks[1]
- if tokCount == 1: return toks[0],[]
- class KeyValueFile( object ):
- '''
- self.data contains a list which holds all the top level Chunk objects
- '''
- def __init__( self, filepath=None, lineParser=parseLine, chunkClass=Chunk, readCallback=None, supportsComments=True ):
- '''
- lineParser needs to return key,value
- '''
- self.filepath = filepath
- self.data = self.value = []
- self.key = None
- self.parent = None
- self.lineParser = lineParser
- self.chunkClass = chunkClass
- self.callback = readCallback
- self.supportsComments = supportsComments
- def nullCallback(*args): pass
- self.nullCallback = nullCallback
- #if no callback is defined, create a dummy one
- if self.callback is None:
- self.callback = nullCallback
- #if no line parser was given, then use a default one
- if self.lineParser is None:
- def simpleLineParse( line ):
- toks = line.split()
- if len(toks) == 1: return toks[0],[]
- else: return toks[0],toks[1]
- self.lineParser = simpleLineParse
- #if a filepath exists, then read it
- if self.filepath.exists:
- self.read()
- def getFilepath( self ):
- return self._filepath
- def setFilepath( self, newFilepath ):
- '''
- this wrapper is here so to ensure the _filepath attribute is a Path instance
- '''
- self._filepath = Path(newFilepath)
- filepath = property(getFilepath, setFilepath)
- def read( self, filepath=None ):
- '''
- reads the actual file, and passes the data read over to the parseLines method
- '''
- if filepath == None: filepath = self.filepath
- else: filepath = Path(filepath)
- self.parseLines( filepath.read() )
- def parseLines( self, lines ):
- '''
- this method does the actual parsing/data creation. deals with comments, passing off data to the lineParser,
- firing off the read callback, all that juicy stuff...
- '''
- lines = [l.strip() for l in lines]
- #remove comments
- if self.supportsComments:
- lines = removeLineComments(lines)
- lines = removeBlockComments(lines)
- numLines = len(lines)
- #hold a list representation of the current spot in the hierarchy
- parentList = [self]
- parentListEnd = self
- callback = self.callback
- lineParser = self.lineParser
- n = 0
- for line in lines:
- #run the callback - if there are any problems, replace the callback with the nullCallback
- try: callback(n,numLines)
- except: callback = self.nullCallback
- if line == '': pass
- elif line == '{':
- curParent = parentList[-1][-1]
- parentList.append(curParent)
- parentListEnd = curParent
- elif line == '}':
- parentList.pop()
- parentListEnd = parentList[-1]
- else:
- try:
- key, value = lineParser(line)
- except TypeError:
- raise TypeError( 'Malformed kevalue found in file near line {0}'.format( n+1 ) )
- parentListEnd.append( self.chunkClass(key, value, parentListEnd) )
- n += 1
- def __getitem__( self, *args ):
- '''
- provides an index based way of accessing file data - self[0,1,2] accesses the third child of
- the second child of the first root element in self
- '''
- args = args[0]
- if not isinstance(args,tuple):
- data = self.data[args]
- else:
- data = self.data[args[0]]
- if len(args) > 1:
- for arg in args[1:]:
- data = data[arg]
- return data
- def __len__( self ):
- '''
- lists the number of root elements in the file
- '''
- return len(self.data)
- def __repr__( self ):
- '''
- this string representation of the file is almost identical to the formatting of a vmf file written
- directly out of hammer
- '''
- strList = []
- for chunk in self.data:
- strList.append( str(chunk) )
- return ''.join(strList)
- __str__ = __repr__
- serialize = __repr__
- def unserialize( self, theString ):
- '''
- '''
- theStringLines = theString.split( '\n' )
- self.parseLines( theStringLines )
- @property
- def hasLen( self ):
- try:
- self.data[ 0 ]
- return True
- except IndexError:
- return False
- def asDict( self ):
- '''
- returns a dictionary representing the key value file - this isn't always possible as it is valid for
- a keyValueFile to have mutiple keys with the same key name within the same level - which obviously
- isn't possible with a dictionary - so beware!
- '''
- asDict = {}
- for chunk in self.data:
- chunk.asDict( asDict )
- return asDict
- def append( self, chunk ):
- '''
- appends data to the root level of this file - provided to make the vmf file object appear
- more like a chunk object
- '''
- self.data.append( chunk )
- def findKey( self, key ):
- '''
- returns a list of all chunks that contain the exact key given
- '''
- matches = []
- for item in self.data:
- matches.extend( item.findKey(key) )
- return matches
- def findValue( self, value ):
- '''
- returns a list of all chunks that contain the exact value given
- '''
- matches = []
- for item in self.data:
- matches.extend( item.findValue(value) )
- return matches
- def findKeyValue( self, key, value ):
- '''
- returns a list of all chunks that have the exact key and value given
- '''
- matches = []
- for item in self.data:
- matches.extend( item.findKeyValue(key,value) )
- return matches
- def testOnValues( self, valueTest ):
- '''
- returns a list of chunks that return true to the method given - the method should take as its
- first argument the value of the chunk it is testing against. can be useful for finding values
- containing substrings, or all compound chunks etc...
- '''
- matches = []
- for item in self.data:
- matches.extend( item.testOnValues(valueTest) )
- return matches
- def write( self, filepath=None, doP4=True ):
- '''
- writes the instance back to disk - optionally to a different location from that which it was
- loaded. NOTE: deals with perforce should the file be managed by p4
- '''
- if filepath is None:
- filepath = self.filepath
- else:
- filepath = Path(filepath)
- filepath.write(str(self), doP4=doP4)
- def resetCache( self ):
- pass
- class GameInfoFile( KeyValueFile ):
- '''
- Provides an interface to gameinfo relevant operations - querying search paths, game root, game title etc...
- '''
- def __init__( self, filepath=None, chunkClass=Chunk, readCallback=None ):
- try:
- project()
- except: return
- if filepath is None:
- filepath = project() / 'gameinfo.gi'
- # look for a gameinfo.txt instead, pick a gameinfo.gi as default if it doesn't exist.
- if not filepath.exists:
- filepath = project() / 'gameinfo.txt'
- if not filepath.exists:
- filepath = project() / 'gameinfo.gi'
- if filepath:
- self.filename = filepath.split()[ - 1 ]
- else:
- self.filename = None
- KeyValueFile.__init__(self, filepath, parseLine, chunkClass, readCallback, True)
- def __getattr__( self, attr ):
- return getattr(self[0],attr)
- def getSearchPaths( self ):
- return [ Path.Join( '%VPROJECT%/../', mod ) for mod in self.getSearchMods() ]
- def getSearchMods( self ):
- #always has the base mod in it...
- searchPaths = [mod()]
- pathsChunk = self.FileSystem.SearchPaths
- paths = [chunk.value for chunk in pathsChunk]
- gi = '|gameinfo_path|'
- sp = '|all_source_engine_paths|'
- for path in paths:
- pos = path.find(gi)
- if pos != -1: continue
- path = path.replace(sp,'')
- if not path: continue
- if path not in searchPaths: searchPaths.append( path )
- return searchPaths
- def getTitle( self ):
- try:
- return self[0].title.value
- except AttributeError:
- try:
- return self[0].game.value
- except:
- return "unknown"
- title = property(getTitle)
- def getEngine( self ):
- try:
- return self[0].ToolsEnvironment.Engine.value
- except AttributeError:
- try:
- return self[0].engine.value
- except:
- return "unknown"
- engine = property( getEngine )
- def getToolsDir( self ):
- try:
- return self[0].ToolsEnvironment.ToolsDir.value
- except AttributeError:
- try:
- return self[0].ToolsDir.value
- except:
- return "unknown"
- toolsDir = property( getToolsDir )
- def writeDefaultFile( self ):
- '''
- Creates a default GameInfo file with basic structure
- '''
- self.filepath.write( '''"GameInfo"\n{\n\tgame "tmp"\n\tFileSystem\n\t{\n\t\tSearchPaths\n'+
- '\t\t{\n\t\t\tGame |gameinfo_path|.\n\t\t}\n\t}\n}''' )
- def simpleValidate( self ):
- '''
- Checks to see if the file has some basic keyvalues
- '''
- try:
- getattr( self[0], 'game' )
- getattr( self[0], 'SearchPaths' )
- return True
- except AttributeError:
- raise GameInfoException( 'Not a valid gameinfo file.' )
- # Read the current gameinfo
- gameInfo = GameInfoFile()
- class GameInfoException(Exception):
- pass
- def lsGamePath( path, recursive=False ):
- '''
- lists all files under a given 'valve path' - ie a game or content relative path. this method needs to iterate
- over all known search mods as defined in a project's gameInfo script
- '''
- path = Path( path )
- files = []
- for modPath in [ base / path for base in gameInfo.getSearchPaths() ]:
- files += list( modPath.files( recursive=recursive ) )
- return files
- def lsContentPath( path, recursive=False ):
- '''
- similar to lsGamePath except that it lists files under the content tree, not the game tree
- '''
- path = Path( path )
- c = content()
- files = []
- for modPath in [ c / mod / path for mod in gameInfo.getSearchMods() ]:
- files += list( modPath.files( recursive=recursive ) )
- return files
- def contentPath( modRelativeContentPath ):
- '''allows you do specify a path using mod relative syntax instead of a fullpath
- example:
- assuming vproject is set to d:/main/game/tf_movies
- contentPath( 'models/player/soldier/parts/maya/soldier_reference.ma' )
- returns: d:/main/content/tf/models/player/soldier/parts/maya/soldier_reference.ma
- NOTE: None is returned in the file can't be found in the mod hierarchy
- '''
- return Path( modRelativeContentPath ).expandAsContent( gameInfo )
- def gamePath( modRelativeContentPath ):
- '''allows you do specify a path using mod relative syntax instead of a fullpath
- example:
- assuming vproject is set to d:/main/game/tf
- gamePath( 'models/player/soldier.mdl' )
- returns: d:/main/game/tf/models/player/soldier.mdl
- NOTE: None is returned in the file can't be found in the mod hierarchy
- '''
- return Path( modRelativeContentPath ).expandAsGame( gameInfo )
- def textureAsGameTexture( texturePath ):
- '''
- returns a resolved game texture filepath given some sort of texture path
- '''
- if not isinstance( texturePath, Path ):
- texturePath = Path( texturePath )
- if texturePath.isAbs():
- if texturePath.isUnder( content() ): relPath = texturePath - content()
- else: relPath = texturePath - game()
- relPath = relPath[ 2: ]
- else:
- relPath = texturePath
- if relPath.startswith( 'materials' ) or relPath.startswith( 'materialsrc' ):
- relPath = relPath[ 1: ]
- relPath = ('materials' / relPath).setExtension( 'vtf' )
- relPath = relPath.expandAsGame( gameInfo )
- return relPath
- def textureAsContentTexture( texturePath ):
- '''
- returns a resolved content texture filepath for some sort of texture path. it looks for psd
- first, and then for tga. if neither are found None is returned
- '''
- if not isinstance( texturePath, Path ):
- texturePath = Path( texturePath )
- xtns = [ 'psd', 'tga' ]
- if texturePath.isAbs():
- if texturePath.isUnder( content() ): relPath = texturePath - content()
- else: relPath = texturePath - game()
- relPath = relPath[ 2: ]
- else:
- relPath = texturePath
- if relPath.startswith( 'materials' ) or relPath.startswith( 'materialsrc' ):
- relPath = relPath[ 1: ]
- contentPath = 'materialsrc' / relPath
- for xtn in xtns:
- tmp = contentPath.expandAsContent( gameInfo, xtn )
- if tmp is None: continue
- return tmp
- return None
- def resolveMaterialPath( materialPath ):
- '''
- returns a resolved material path given some sort of material path
- '''
- if not isinstance( materialPath, Path ):
- materialPath = Path( materialPath )
- if materialPath.isAbs():
- if materialPath.isUnder( content() ): relPath = materialPath - content()
- else: relPath = materialPath - game()
- relPath = relPath[ 2: ]
- else:
- relPath = materialPath
- if relPath.startswith( 'materials' ) or relPath.startswith( 'materialsrc' ):
- relPath = relPath[ 1: ]
- relPath = ('materials' / relPath).setExtension( 'vmt' )
- relPath = relPath.expandAsGame( gameInfo )
- return relPath
- #end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement