mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-08 01:39:36 +00:00
1
This commit is contained in:
@@ -0,0 +1,259 @@
|
||||
|
||||
|
||||
import os, sys
|
||||
|
||||
|
||||
class PySSException:
|
||||
pass
|
||||
|
||||
|
||||
g_bVerbose = 0
|
||||
|
||||
|
||||
class PySourceSafe:
|
||||
"""
|
||||
PySourceSafe represents a connection to a SS database.
|
||||
Pass the directory to the database in the constructor, or \\hl2vss\hl2vss is assumed.
|
||||
"""
|
||||
|
||||
def __init__( self, dbPath=r"\\hl2vss\hl2vss" ):
|
||||
# Store this off so we can put it in the environment when we run ss.
|
||||
self.m_DBPath = dbPath
|
||||
self.bUseExceptions = 0
|
||||
|
||||
self.m_VSSCommand = None
|
||||
|
||||
# Since we can't use spawnvpe to have it find ss.exe for us, we have to look in the path for it manually.
|
||||
paths = os.environ['path'].split( ';' )
|
||||
for path in paths:
|
||||
if path[-1:] == '/' or path[-1:] == '\\':
|
||||
testFilename = path + 'ss.exe'
|
||||
else:
|
||||
testFilename = path + '\\' + 'ss.exe'
|
||||
|
||||
testFilename = testFilename.replace( '\"', '' )
|
||||
if os.access( testFilename, os.F_OK ):
|
||||
self.m_VSSCommand = testFilename
|
||||
break
|
||||
|
||||
# If we can't find the vss command, they we're screwed so throw an exception.
|
||||
if not self.m_VSSCommand:
|
||||
raise PySSException
|
||||
|
||||
for_cmd = 'for %I in ("' + self.m_VSSCommand + '") do echo %~sI'
|
||||
p = os.popen(for_cmd)
|
||||
self.m_VSSCommand = p.readlines()[-1] # last line from for command
|
||||
p.close()
|
||||
|
||||
self.m_VSSCommand = self.m_VSSCommand.replace( '\n', '' )
|
||||
self.lastExitStatus = 0
|
||||
self.m_LastCommandOutput = ''
|
||||
|
||||
|
||||
# Throw an exception on error? Default is no.
|
||||
def EnableExceptions( self, bEnable ):
|
||||
self.bUseExceptions = 1
|
||||
|
||||
|
||||
# Get the output from the last command.
|
||||
# This returns a list of the lines of text with the output.
|
||||
def GetLastCommandOutput():
|
||||
return self.m_LastCommandOutput
|
||||
|
||||
|
||||
# Return a list of the filenames in a directory.
|
||||
def ListFiles( self, rootDir ):
|
||||
outlines = self.__RunCommand( ['dir',rootDir] )
|
||||
if not outlines:
|
||||
return None
|
||||
|
||||
returnList = []
|
||||
for i in range( 1, len( outlines ) ):
|
||||
if len( outlines[i] ) == 0:
|
||||
break
|
||||
elif outlines[i][0:1] != '$':
|
||||
returnList.append( outlines[i] )
|
||||
|
||||
return returnList
|
||||
|
||||
|
||||
def ListDirectories( self, rootDir ):
|
||||
outlines = self.__RunCommand( ['dir',rootDir] )
|
||||
if not outlines:
|
||||
return None
|
||||
|
||||
returnList = []
|
||||
for i in range( 1, len( outlines ) ):
|
||||
if len( outlines[i] ) == 0:
|
||||
break
|
||||
elif outlines[i][0:1] == '$':
|
||||
returnList.append( outlines[i] )
|
||||
|
||||
return returnList
|
||||
|
||||
|
||||
# Example: p.AddFile( "$/hl2/release/dev/hl2/scripts", "c:\\test.txt", "some comment here" )
|
||||
def AddFile( self, vssDir, localFilename, comment=None ):
|
||||
if not self.__RunCommand( ['cp', vssDir] ):
|
||||
return None
|
||||
|
||||
args = ['add', localFilename, '-I-']
|
||||
if comment:
|
||||
args.append( '-C%s' % comment )
|
||||
|
||||
return self.__RunCommand( args )
|
||||
|
||||
|
||||
# Create a new directory (or 'subproject').
|
||||
# Example: p.CreateDirectory( '$/tfc/models/test' )
|
||||
# Note: this WILL create the subdirectories leading up to the final one if they don't exist.
|
||||
def CreateDirectory( self, vssDir, comment=None ):
|
||||
if not comment:
|
||||
comment = ''
|
||||
|
||||
lastRet = []
|
||||
|
||||
# Create all directories leading up to this one/
|
||||
dirs = vssDir.split( '/' )
|
||||
curDir = ''
|
||||
for dir in dirs:
|
||||
if len( curDir ) == 0:
|
||||
curDir = dir
|
||||
else:
|
||||
curDir = curDir + '/' + dir
|
||||
|
||||
# Does it exist already?
|
||||
self.__RunCommand( ['properties', curDir], 0 )
|
||||
if self.lastExitStatus != 0 and self.lastExitStatus != None:
|
||||
lastRet = self.__RunCommand( ['create', curDir, '-C%s' % comment, '-I-'] )
|
||||
if lastRet == None:
|
||||
break
|
||||
|
||||
return lastRet
|
||||
|
||||
|
||||
# Remove a file. Returns:
|
||||
# 0 if the file doesn't exist
|
||||
# 1 if it existed and was removed
|
||||
# None if the file existed but there was an error.
|
||||
def DeleteFile( self, vssFilename ):
|
||||
self.__RunCommand( ['properties', vssFilename], 0 )
|
||||
if self.lastExitStatus:
|
||||
return 0
|
||||
else:
|
||||
# Now try to remove it.
|
||||
self.__RunCommand( ['delete', vssFilename, '-I-'] )
|
||||
if self.lastExitStatus:
|
||||
return None
|
||||
else:
|
||||
return 1
|
||||
|
||||
|
||||
# Get the checkout status of a file (and find out if the file even exists).
|
||||
def GetFileStatus( self, ssFilename ):
|
||||
pass
|
||||
|
||||
|
||||
# Get the local working directory for the specified SS directory.
|
||||
def GetWorkingDirectory( self, ssDir ):
|
||||
pass
|
||||
|
||||
|
||||
# Get the local filename for the specified file.
|
||||
def GetLocalFilename( self, ssFilename ):
|
||||
pass
|
||||
|
||||
|
||||
# For all the CheckOut and Get commands, if localFilename is not None, then it'll
|
||||
# treat that as the local file. Otherwise, it'll use the default working directory for that directory in SS.
|
||||
# Returns 1 if successful, 0 if there was an error.
|
||||
|
||||
# Check out a file.
|
||||
# Use GetLastOutput() to get the output string.
|
||||
def CheckOutFile( self, ssFilename, localFilename=None ):
|
||||
pass
|
||||
|
||||
|
||||
# Check out the whole directory.
|
||||
def CheckOutDir( self, ssDirName, localDirName=None, bRecursive=0 ):
|
||||
pass
|
||||
|
||||
|
||||
# Get a file.
|
||||
def GetFile( self, ssFilename, localFilename=None ):
|
||||
pass
|
||||
|
||||
|
||||
# Get a whole directory.
|
||||
def GetFile( self, ssFilename, localFilename=None ):
|
||||
pass
|
||||
|
||||
# Check in a file. Optionally specify a comment.
|
||||
# Returns 1 if successful, 0 otherwise.
|
||||
def CheckInFile( self, ssFilename, localFilename=None, comment=None ):
|
||||
pass
|
||||
|
||||
|
||||
# The big master function to run a vss command and get the results back in a list.
|
||||
def __RunCommand( self, args, bHandleErrors=1 ):
|
||||
# First, set the environment up.
|
||||
tempEnviron = os.environ
|
||||
os.environ['ssdir'] = self.m_DBPath
|
||||
|
||||
# Now build the command.
|
||||
cmd = self.m_VSSCommand
|
||||
for i in args:
|
||||
cmd = cmd + ' \"%s\"' % i
|
||||
|
||||
if g_bVerbose:
|
||||
print "VSS: " + cmd
|
||||
|
||||
# Run the command and capture its output.
|
||||
f = os.popen( cmd, 'r' )
|
||||
lines = f.readlines()
|
||||
self.lastExitStatus = f.close()
|
||||
|
||||
self.m_LastCommandOutput = lines
|
||||
lines = [i.strip() for i in lines]
|
||||
|
||||
# Restore the environment.
|
||||
os.environ = tempEnviron
|
||||
|
||||
if self.lastExitStatus != 0 and self.lastExitStatus != None:
|
||||
if bHandleErrors:
|
||||
print 'VSS Error (status: %d): ' % self.lastExitStatus
|
||||
print 'cmd: %s' % cmd
|
||||
print 'output: '
|
||||
for i in lines:
|
||||
print '\t%s' % i
|
||||
|
||||
if self.bUseExceptions:
|
||||
raise PySSException
|
||||
else:
|
||||
return None
|
||||
|
||||
return lines
|
||||
|
||||
|
||||
|
||||
p = PySourceSafe()
|
||||
|
||||
|
||||
# TEST CODE
|
||||
"""
|
||||
print "Files"
|
||||
files = p.ListFiles( '$/hl2/release/dev' )
|
||||
for i in files:
|
||||
print i
|
||||
|
||||
print "\n\nDirectories"
|
||||
files = p.ListDirectories( '$/hl2/release/dev' )
|
||||
for i in files:
|
||||
print i
|
||||
|
||||
|
||||
vssRoot = '$/tfc/models'
|
||||
p.AddFile( "$/tfc", "c:\\test.txt", "test comment blah blah" )
|
||||
|
||||
p.CreateDirectory( '$/tfc/aa/bb/cc/dd', 'here is hte comment' )
|
||||
"""
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
STOP_RECURSING = 23452
|
||||
|
||||
|
||||
class VisitFiles:
|
||||
"""
|
||||
This is a helper class to visit a bunch of files in a tree given
|
||||
the regular expressions that will match the filenames you're interested in.
|
||||
|
||||
Create this class like a function, and pass in these parameters:
|
||||
baseDir - a string for the root directory in the search. This must not end in a slash.
|
||||
|
||||
fileMasks - a list of strings that contain regular expressions for filenames you want to match.
|
||||
|
||||
fileCB - This function is called for each filename matched. It takes these parameters:
|
||||
- short filename ("blah.txt")
|
||||
- relative filename ("a/b/c/blah.txt")
|
||||
- long filename ("c:/basedir/a/b/c/blah.txt")
|
||||
|
||||
dirCB - a function called for each directory name. This can be None. If it returns STOP_RECURSING,
|
||||
then it won't do callbacks for the files and directories under this one.
|
||||
- relative dirName ("./a/b")
|
||||
- full dirname (from the baseDir you pass into __init__) ("d:/a/b")
|
||||
|
||||
bRecurse - a boolean telling whether or not to recurse into other directories.
|
||||
|
||||
Example: This would visit all files recursively (.+ matches any non-zero-length string).
|
||||
VisitFiles( ".", [".+"], MyCallback )
|
||||
"""
|
||||
|
||||
def __init__( self, baseDir, fileMasks, fileCB, dirCB, bRecurse=1 ):
|
||||
# Handle it appropriately whether they pass 1 filemask or a list of them.
|
||||
if isinstance( fileMasks, list ):
|
||||
self.fileMasks = [re.compile( x, re.IGNORECASE ) for x in fileMasks]
|
||||
else:
|
||||
self.fileMasks = [re.compile( fileMasks, re.IGNORECASE )]
|
||||
|
||||
self.fileCB = fileCB
|
||||
self.dirCB = dirCB
|
||||
self.bRecurse = bRecurse
|
||||
|
||||
self.__VisitFiles_R( ".", baseDir )
|
||||
|
||||
|
||||
def __RemoveDotSlash( self, name ):
|
||||
if name[0:2] == '.\\':
|
||||
return name[2:]
|
||||
else:
|
||||
return name
|
||||
|
||||
|
||||
def __VisitFiles_R( self, relativeDirName, baseDirName ):
|
||||
if self.dirCB:
|
||||
if self.dirCB( relativeDirName, baseDirName ) == 0:
|
||||
return
|
||||
|
||||
files = os.listdir( baseDirName )
|
||||
|
||||
for filename in files:
|
||||
upperFilename = filename.upper()
|
||||
fullFilename = self.__RemoveDotSlash( baseDirName + "\\" + filename )
|
||||
relativeName = self.__RemoveDotSlash( relativeDirName + "\\" + filename )
|
||||
|
||||
stats = os.stat( fullFilename )
|
||||
if stats[0] & (1<<15):
|
||||
|
||||
matched = 0
|
||||
for curRE in self.fileMasks:
|
||||
if curRE.search( upperFilename ):
|
||||
matched = 1
|
||||
break
|
||||
|
||||
if matched:
|
||||
self.fileCB( filename, relativeName, fullFilename )
|
||||
else:
|
||||
|
||||
# It's a directory.
|
||||
if self.bRecurse:
|
||||
self.__VisitFiles_R( relativeName, fullFilename )
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
from __future__ import generators
|
||||
import os
|
||||
import re
|
||||
import stat
|
||||
|
||||
|
||||
# This takes a DOS filename wildcard like *abc.t?t and returns a regex string that will match it.
|
||||
def GetRegExForDOSWildcard( wildcard ):
|
||||
# First find the base directory name.
|
||||
iLast = wildcard.rfind( "/" )
|
||||
if iLast == -1:
|
||||
iLast = wildcard.rfind( "\\" )
|
||||
|
||||
if iLast == -1:
|
||||
dirName = "."
|
||||
dosStyleWildcard = wildcard
|
||||
else:
|
||||
dirName = wildcard[0:iLast]
|
||||
dosStyleWildcard = wildcard[iLast+1:]
|
||||
|
||||
# Now generate a regular expression for the search.
|
||||
# DOS -> RE
|
||||
# * -> .*
|
||||
# . -> \.
|
||||
# ? -> .
|
||||
reString = dosStyleWildcard.replace( ".", r"\." ).replace( "*", ".*" ).replace( "?", "." ) + r'\Z'
|
||||
return reString
|
||||
|
||||
|
||||
#
|
||||
# Useful function to return a list of files in a directory based on a dos-style wildcard like "*.txt"
|
||||
#
|
||||
# for name in WildcardSearch( "d:/hl2/src4/dt*.cpp", 1 ):
|
||||
# print name
|
||||
#
|
||||
def WildcardSearch( wildcard, bRecurse=0 ):
|
||||
reString = GetRegExForDOSWildcard( wildcard )
|
||||
matcher = re.compile( reString, re.IGNORECASE )
|
||||
|
||||
return __GetFiles_R( matcher, dirName, bRecurse )
|
||||
|
||||
def __GetFiles_R( matcher, dirName, bRecurse ):
|
||||
fileList = []
|
||||
# For each file, see if we can find the regular expression.
|
||||
files = os.listdir( dirName )
|
||||
for baseName in files:
|
||||
filename = dirName + "/" + baseName
|
||||
|
||||
mode = os.stat( filename )[stat.ST_MODE]
|
||||
if stat.S_ISREG( mode ):
|
||||
# Make sure the file matches the search string.
|
||||
if matcher.match( baseName ):
|
||||
fileList.append( filename )
|
||||
|
||||
elif bRecurse and stat.S_ISDIR( mode ):
|
||||
fileList += __GetFiles_R( matcher, filename, bRecurse )
|
||||
|
||||
return fileList
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
import stat
|
||||
|
||||
|
||||
g_NumSoundsAdded = 0
|
||||
|
||||
|
||||
def ScanSounds_R( baseDir, relativeDir, outFile ):
|
||||
files = os.listdir( baseDir )
|
||||
for filename in files:
|
||||
fullFilename = baseDir + "\\" + filename
|
||||
if len( relativeDir ) > 0:
|
||||
newRelativeDir = relativeDir + "/" + filename
|
||||
else:
|
||||
newRelativeDir = filename
|
||||
|
||||
mode = os.stat( fullFilename )[stat.ST_MODE]
|
||||
|
||||
if stat.S_ISREG( mode ):
|
||||
if filename[-4:].upper() == ".WAV":
|
||||
outFile.write( "\"%s\"\n" % ( newRelativeDir[0:-4] ) )
|
||||
outFile.write( "{\n" )
|
||||
outFile.write( "\t\"channel\"\t\t\"CHAN_ITEM\"\n" )
|
||||
outFile.write( "\t\"volume\"\t\t\"VOL_NORM\"\n" )
|
||||
outFile.write( "\t\"soundlevel\"\t\"SNDLVL_NONE\"\n" )
|
||||
outFile.write( "\t\"pitch\"\t\t\t\"PITCH_NORM\"\n" )
|
||||
outFile.write( "\t\"wave\"\t\t\t\"%s\"\n" % ( newRelativeDir ) )
|
||||
outFile.write( "}\n\n" )
|
||||
|
||||
global g_NumSoundsAdded
|
||||
g_NumSoundsAdded += 1
|
||||
|
||||
if stat.S_ISDIR( mode ):
|
||||
ScanSounds_R( fullFilename, newRelativeDir, outFile )
|
||||
|
||||
|
||||
# Make sure we've got a valid base directory.
|
||||
if len( sys.argv ) < 2:
|
||||
print "Error: Must specify the root sound directory."
|
||||
sys.exit( 1 )
|
||||
|
||||
baseDir = sys.argv[1]
|
||||
if os.access( baseDir, os.R_OK ) != 1:
|
||||
print "Error: Can't access %s." % ( baseDir )
|
||||
sys.exit( 1 )
|
||||
|
||||
|
||||
# Now scan all the .cpp files for sound function calls.
|
||||
outFile = open( "game_sounds.txt", "wt" )
|
||||
|
||||
ScanSounds_R( baseDir, "", outFile )
|
||||
|
||||
outFile.close()
|
||||
|
||||
|
||||
print "Added %d sounds to game_sounds.txt" % ( g_NumSoundsAdded )
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
|
||||
# This script converts old 9 way blends that look like this:
|
||||
#
|
||||
# $sequence crouch_tommy_shoot "crouch_tommy_shootupL" "crouch_tommy_shootup" "crouch_tommy_shootupR" "crouch_tommy_shootmidL" "crouch_tommy_shootmid" "crouch_tommy_shootmidR" "crouch_tommy_shootdownL" "crouch_tommy_shootdown" "crouch_tommy_shootdownL" blend XR 45 -45 fps 30 origin 0 0 17 { event 7002 1 "1" }
|
||||
#
|
||||
# to this:
|
||||
#
|
||||
# $sequence crouch_tommy_shoot {
|
||||
# "crouch_tommy_shootupL" "crouch_tommy_shootup" "crouch_tommy_shootupR"
|
||||
# "crouch_tommy_shootmidL" "crouch_tommy_shootmid" "crouch_tommy_shootmidR"
|
||||
# "crouch_tommy_shootdownL" "crouch_tommy_shootdown" "crouch_tommy_shootdownL"
|
||||
# blendwidth 3 blend body_yaw -45 45 blend body_pitch -65 65
|
||||
# fps 30 origin 0 0 17 { event 7002 1 "1" }
|
||||
# }
|
||||
|
||||
import sys
|
||||
import re
|
||||
import string
|
||||
|
||||
if len( sys.argv ) < 3:
|
||||
print "Requires 2 parameters: <input file> <output file>"
|
||||
sys.exit( 1 )
|
||||
|
||||
|
||||
# Read in the file.
|
||||
f = open( sys.argv[1], "rt" )
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
|
||||
|
||||
# Do the search/replace.
|
||||
def named( re, name ):
|
||||
return r'(?P<' + name + r'>' + re + ')'
|
||||
|
||||
def ident( animName ):
|
||||
if animName:
|
||||
return named( r'\"?\S+\"?', animName )
|
||||
else:
|
||||
return r'\"?\S+\"?'
|
||||
|
||||
|
||||
ws = r'\s*'
|
||||
|
||||
# THIS IS THE FIRST PASS - ADDS THE 9-WAY BLENDS
|
||||
if 1:
|
||||
nineNames = [ws+ident('a'+str(i)) for i in range(1,10)]
|
||||
sequenceAndAnims = named( r'\s*', 'prefix' ) + r'\$sequence' + ws + ident('animName') + string.join( nineNames, '' )
|
||||
|
||||
# NOTE THERE IS A KNOWN BUG HERE - extra NEEDS TO INCLUDE THE 'blend xr -45 45' STUFF SO WE CAN STRIP IT OUT
|
||||
extra = ws + ident('blend') + named( '.+', 'extra' )
|
||||
myRE = re.compile( sequenceAndAnims + extra )
|
||||
|
||||
#lines = ['$sequence crouch_pistol_aim "crouch_pistol_aimupL" "crouch_pistol_aimup" "crouch_pistol_aimupR" "crouch_pistol_aimmidL" "crouch_pistol_aimmid" "crouch_pistol_aimmidR" "crouch_pistol_aimdownL" "crouch_pistol_aimdown" "crouch_pistol_aimdownR" loop blend XR 45 -45 fps 30 origin 0 0 17']
|
||||
|
||||
outLines = []
|
||||
for curLine in lines:
|
||||
m = myRE.match( curLine )
|
||||
if m and (m.group('blend') == 'blend' or m.group('blend') == 'loop'):
|
||||
prefix = m.group('prefix')
|
||||
curLine = prefix + '$sequence %s {\n' % m.group('animName')
|
||||
curLine += prefix + '\t%s %s %s\n' % ( m.group('a1'), m.group('a2'), m.group('a3') )
|
||||
curLine += prefix + '\t%s %s %s\n' % ( m.group('a4'), m.group('a5'), m.group('a6') )
|
||||
curLine += prefix + '\t%s %s %s\n' % ( m.group('a7'), m.group('a8'), m.group('a9') )
|
||||
curLine += prefix + '\tblendwidth 3 blend body_yaw -45 45 blend body_pitch -65 65\n'
|
||||
curLine += prefix + '\t' + m.group( 'extra' ) + '\n'
|
||||
curLine += prefix + '}\n\n'
|
||||
|
||||
outLines.append( curLine )
|
||||
|
||||
# THIS IS THE SECOND PASS - IT ADDS THE UPPER-BODY WEIGHTLISTS
|
||||
if 0:
|
||||
lookFor = named( r'\s*', 'start' ) + named( r'blendwidth 3 blend body_yaw -45 45 blend body_pitch -65 65', 'mid' ) + named( r'\s*', 'end' )
|
||||
myRE = re.compile( lookFor )
|
||||
|
||||
outLines = []
|
||||
for curLine in lines:
|
||||
m = myRE.match( curLine )
|
||||
if m:
|
||||
curLine = curLine + m.group('start') + 'weightlist upperbody\n'
|
||||
|
||||
outLines.append( curLine )
|
||||
|
||||
|
||||
# Save the output file.
|
||||
f = open( sys.argv[2], "wt" )
|
||||
f.writelines( outLines )
|
||||
f.close()
|
||||
@@ -0,0 +1,226 @@
|
||||
|
||||
import msvcrt, os, sys, re, WildcardSearch, VisitFiles
|
||||
|
||||
|
||||
def GetArg( argName, ifAtEnd='' ):
|
||||
for i in range( 1, len( sys.argv ) ):
|
||||
if argName.upper() == sys.argv[i].upper():
|
||||
if i+1 >= len( sys.argv ):
|
||||
return ifAtEnd
|
||||
else:
|
||||
return sys.argv[i+1]
|
||||
return None
|
||||
|
||||
|
||||
def PrintUsage():
|
||||
print r'port_models.py -srcdir <directory with the QCs> -vproject <game directory>'
|
||||
print r'Note: -srcdir represents the ROOT of the models directory, but it points at the model sources'
|
||||
print r' instead of the model content.'
|
||||
print r'ex: port_models.py -srcdir c:\hl2\models\tfc -vproject c:\hl2\tfc'
|
||||
sys.exit( 1 )
|
||||
|
||||
|
||||
def FixFilename( filename ):
|
||||
filename = filename.replace( '/', '\\' )
|
||||
if filename == '.\\':
|
||||
return filename
|
||||
else:
|
||||
return re.compile( r'[^\.]?\.\\' ).sub( '', filename )
|
||||
|
||||
|
||||
def GetDirName( fullFilename ):
|
||||
a = fullFilename.rfind( '/' )
|
||||
b = fullFilename.rfind( '\\' )
|
||||
if a == -1 and b == -1:
|
||||
return FixFilename( fullFilename )
|
||||
else:
|
||||
return FixFilename( fullFilename[0 : max(a,b)] )
|
||||
|
||||
|
||||
g_bAlwaysContinue = 0
|
||||
def CheckContinue():
|
||||
global g_bAlwaysContinue
|
||||
if g_bAlwaysContinue:
|
||||
return 1
|
||||
else:
|
||||
sys.stdout.write( 'Continue [(Y)es/(N)o/(A)lways]? ' )
|
||||
r = str( msvcrt.getch() ).upper()
|
||||
if r == 'Y':
|
||||
return 1
|
||||
elif r == 'A':
|
||||
g_bAlwaysContinue = 1
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
#
|
||||
# Get command line args.
|
||||
#
|
||||
modelSourceDir = GetArg( '-srcdir' )
|
||||
vprojectDir = GetArg( '-vproject' )
|
||||
if not modelSourceDir or not vprojectDir:
|
||||
PrintUsage()
|
||||
|
||||
binDir = vprojectDir + '\\..\\bin'
|
||||
|
||||
studiomdlFilename = binDir + '\\studiomdl.exe'
|
||||
vtexFilename = binDir + '\\vtex.exe'
|
||||
xwadFilename = binDir + '\\xwad.exe'
|
||||
if not os.access( studiomdlFilename, os.F_OK ) or not os.access( vtexFilename, os.F_OK ) or not os.access( xwadFilename, os.F_OK ):
|
||||
print 'Can\'t find vtex.exe, xwad.exe, or studiomdl.exe in bin directory %s.' % (binDir)
|
||||
sys.exit( 1 )
|
||||
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
# REGEX's and code to convert the QC file.
|
||||
#
|
||||
#
|
||||
reModelName = re.compile( r'(?P<start>\$modelname\s+)(?P<stripout>.*models(\\|\/))(?P<keep>.+)', re.IGNORECASE )
|
||||
reCDTexture = re.compile( r'(?P<start>\$(cdTexture|cdmaterials)\s+)(?P<stripout>.*models(\\|\/))(?P<keep>.+)', re.IGNORECASE )
|
||||
reCD = re.compile( r'\$cd\s', re.IGNORECASE )
|
||||
|
||||
def ident( name=None ):
|
||||
if name:
|
||||
return r'(?P<' + name + r'>\s+((\".*?\")|([^\"]\S*)))'
|
||||
else:
|
||||
return r'\s+((\".*?\")|([^\"]\S*))'
|
||||
|
||||
reAttachmentLine = re.compile( r'(?P<keep>.*\$attachment'+ident()+ident()+ident()+ident()+ident() + ')' + ident()+ident(), re.IGNORECASE )
|
||||
|
||||
g_DirToMaterialsMap = {}
|
||||
|
||||
def EditQCFile( fullFilename ):
|
||||
f = open( fullFilename, 'rt' )
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
|
||||
bDidMaterials = 0
|
||||
|
||||
outLines = []
|
||||
for line in lines:
|
||||
if not reCD.search( line ):
|
||||
# Strip out stuff before /models in the $modelname line.
|
||||
m = reModelName.search( line )
|
||||
if m:
|
||||
line = m.group('start') + m.group('keep' ) + '\n'
|
||||
else:
|
||||
m = reCDTexture.search( line )
|
||||
if m:
|
||||
materialsDirName = 'models/' + m.group('keep')
|
||||
bmpDir = m.group('keep')
|
||||
g_DirToMaterialsMap[FixFilename(bmpDir.upper())] = materialsDirName
|
||||
bDidMaterials = 1
|
||||
line = '$cdmaterials %s\n' % materialsDirName
|
||||
|
||||
# Strip out the last 2 args on the $attachment line if they're using too many.
|
||||
# Goldsrc studiomdl allowed 2 extra args but it ignored them.
|
||||
m = reAttachmentLine.search( line )
|
||||
if m:
|
||||
line = m.group('keep')
|
||||
|
||||
outLines.append( line )
|
||||
|
||||
if not bDidMaterials:
|
||||
print 'No $cdtexture line in %s so we don\'t know where to convert the BMPs into.' % (fullFilename)
|
||||
sys.exit( 1 )
|
||||
|
||||
#
|
||||
# Write the QC back out.
|
||||
#
|
||||
try:
|
||||
f = open( fullFilename, 'wt' )
|
||||
except IOError:
|
||||
print 'Can\'t open %s for writing.\nMake sure it is not read-only.' % fullFilename
|
||||
sys.exit( 1 )
|
||||
f.writelines( outLines )
|
||||
f.close()
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Convert all the QC files and backup the old ones.
|
||||
#
|
||||
print '--- Converting QC files and running studiomdl ---'
|
||||
|
||||
def QCFileCallback( filename, relativeName, fullFilename ):
|
||||
print '\t' + relativeName
|
||||
|
||||
# First, backup the QC.
|
||||
os.system( 'copy \"%s\" \"%s\" > out' % (fullFilename, fullFilename + ".OLD") )
|
||||
|
||||
#
|
||||
# Now, make some edits.
|
||||
#
|
||||
EditQCFile( fullFilename );
|
||||
|
||||
#
|
||||
# Run studiomdl on it.
|
||||
#
|
||||
cmd = '%s -vproject \"%s\" \"%s\" > out' % (studiomdlFilename, vprojectDir, fullFilename)
|
||||
if os.system( cmd ) != 0:
|
||||
lines = open( 'out', 'rt' ).readlines()
|
||||
sys.stdout.writelines( lines )
|
||||
sys.exit( 1 )
|
||||
|
||||
VisitFiles.VisitFiles( modelSourceDir, WildcardSearch.GetRegExForDOSWildcard( '*.qc' ), QCFileCallback, None )
|
||||
|
||||
|
||||
#
|
||||
# Now convert all the BMP files.
|
||||
#
|
||||
print '\n--- Converting BMP files and running vtex ---'
|
||||
def BMPFileCallback( filename, relativeName, fullFilename ):
|
||||
print '\t' + relativeName
|
||||
|
||||
# Find out where we want to store this BMP's files under materials.
|
||||
dirName = GetDirName( relativeName )
|
||||
|
||||
try:
|
||||
cdMaterials = g_DirToMaterialsMap[dirName.upper()]
|
||||
except:
|
||||
#print '\tWarning: couldn\'t convert %s (don\'t know where to put it).' % (relativeName)
|
||||
pass
|
||||
else:
|
||||
#
|
||||
# Run XWAD.
|
||||
#
|
||||
cmd = '%s -quiet -bmpfile \"%s\" -basedir \"%s\"' % (xwadFilename, fullFilename, vprojectDir)
|
||||
if os.system( cmd ) != 0:
|
||||
print '\tError running xwad on %s' % fullFilename
|
||||
if not CheckContinue():
|
||||
print '\tcmd: %s' % cmd
|
||||
sys.exit( 1 )
|
||||
|
||||
#
|
||||
# Move the TGA it generated into the right directory.
|
||||
#
|
||||
materialsrcDir = '%s\\materialsrc\\%s' % (vprojectDir, cdMaterials)
|
||||
if not os.access( materialsrcDir, os.F_OK ) and os.system( 'md \"%s\"' % materialsrcDir ) != 0:
|
||||
print 'Can\'t create or access directory %s.' % materialsrcDir
|
||||
|
||||
materialsDir = '%s\\materials\\%s' % (vprojectDir, cdMaterials)
|
||||
if not os.access( materialsDir, os.F_OK ) and os.system( 'md \"%s\"' % materialsDir ) != 0:
|
||||
print 'Can\'t create or access directory %s.' % materialsDir
|
||||
|
||||
baseTGAFilename = filename[0:-4] + '.tga'
|
||||
generatedFilename = vprojectDir + '\\materialsrc\\' + baseTGAFilename
|
||||
cmd = 'move \"%s\" \"%s\"' % (generatedFilename, materialsrcDir)
|
||||
if os.system( cmd ) != 0:
|
||||
print 'system( %s ) failed.' % cmd
|
||||
|
||||
#
|
||||
# Lastly, run vtex on it.
|
||||
#
|
||||
cmd = '%s -shader VertexLitGeneric -quiet \"%s\\%s\"' % (vtexFilename, materialsrcDir, baseTGAFilename)
|
||||
if os.system( cmd ) != 0:
|
||||
sys.exit( 1 )
|
||||
|
||||
|
||||
VisitFiles.VisitFiles( modelSourceDir, WildcardSearch.GetRegExForDOSWildcard( '*.bmp' ), BMPFileCallback, None )
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
#
|
||||
# This script is used to take a goldsrc-style character model with the origin at
|
||||
# its centerpoint and put its origin at its feet.
|
||||
#
|
||||
# It parses a .qc file, takes all $origin commands, and subtracts that amount
|
||||
# from all 'origin' blocks inside a sequence command.
|
||||
#
|
||||
# Redirect its output to a file (or the input file).
|
||||
#
|
||||
|
||||
import sys
|
||||
import re
|
||||
|
||||
f = open( sys.argv[1], "rt" )
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
|
||||
re1 = re.compile( r'\$origin (?P<x>-?\d+)\s+(?P<y>-?\d+)\s+(?P<z>-?\d+)' )
|
||||
re2 = re.compile( r'(?P<ws>\s)origin (?P<x>-?\d+)\s+(?P<y>-?\d+)\s+(?P<z>-?\d+)' )
|
||||
|
||||
curOffset = [0,0,0]
|
||||
|
||||
def OriginOffset( m ):
|
||||
testOffset = [ int(m.group('x')), int(m.group('y')), int(m.group('z')) ]
|
||||
return '%sorigin %d %d %d' % (m.group('ws'), testOffset[0]-curOffset[0], testOffset[1]-curOffset[1], testOffset[2]-curOffset[2])
|
||||
|
||||
for line in lines:
|
||||
m = re1.search( line )
|
||||
if m:
|
||||
#print 'match: %s %s %s' % ( m.group('x'), m.group('y'), m.group('z') )
|
||||
curOffset = [ int(m.group('x')), int(m.group('y')), int(m.group('z')) ]
|
||||
|
||||
sys.stdout.write( re2.sub( OriginOffset, line ) )
|
||||
|
||||
Reference in New Issue
Block a user