Hello.
I have a Python script that is supposed to build up my client.
Running them one after another you cleanse .pyc files, prepare the client, write files, build client and DONE.
I am trying to prepare_client.
Code of the Python file:
import argparse
import hashlib
import os
import shutil
import subprocess
from pandac.PandaModules import *
import pytz
parser = argparse.ArgumentParser()
parser.add_argument('--distribution', default='en',
help='The distribution token.')
parser.add_argument('--build-dir', default='build',
help='The directory in which to store the build files.')
parser.add_argument('--src-dir', default='toontown',
help='The directory of the Toontown source code.')
parser.add_argument('--server-ver', default='tti-REVISION',
help='The server version of this build.\n'
'REVISION tokens will be replaced with the current Git revision string.')
parser.add_argument('--build-mfs', action='store_true',
help='When present, multifiles will be built.')
parser.add_argument('--resources-dir', default='RetroResources',
help='The directory of the Toontown resources.')
parser.add_argument('modules', nargs='*', default=['shared', 'infinite'],
help='The Toontown modules to be included in the build.')
args = parser.parse_args()
print 'Preparing the client...'
# Create a clean build directory for us to store our build material:
if not os.path.exists(args.build_dir):
os.mkdir(args.build_dir)
print 'Build directory = {0}'.format(args.build_dir)
# This next part is only required if the invoker wants to include the Git
# revision string in their server version:
revision = ''
if 'REVISION' in args.server_ver:
# If we don't have Git on our path, let's attempt to add it:
paths = (
'{0}\\Git\\bin'.format(os.environ['ProgramFiles']),
'{0}\\Git\\cmd'.format(os.environ['ProgramFiles'])
)
for path in paths:
if path not in os.environ['PATH']:
os.environ['PATH'] += ';' + path
# Now, let's get that revision string:
revision = subprocess.Popen(
['git', 'rev-parse', 'HEAD'],
stdout=subprocess.PIPE,
cwd=args.src_dir).stdout.read().strip()[:7]
# Replace any REVISION tokens in the server version:
serverVersion = args.server_ver.replace('REVISION', revision)
print 'serverVersion = {0}'.format(serverVersion)
# Copy the provided Toontown modules:
# NonRepeatableRandomSourceUD.py, and NonRepeatableRandomSourceAI.py are
# required to be included. This is because they are explicitly imported by the
# DC file:
includes = ('NonRepeatableRandomSourceUD.py', 'NonRepeatableRandomSourceAI.py')
# This is a list of explicitly excluded files:
excludes = ('ServiceStart.py')
def minify(f):
"""
Returns the "minified" file data with removed __debug__ code blocks.
"""
data = ''
debugBlock = False # Marks when we're in a __debug__ code block.
elseBlock = False # Marks when we're in an else code block.
# The number of spaces in which the __debug__ condition is indented:
indentLevel = 0
for line in f:
thisIndentLevel = len(line) - len(line.lstrip())
if ('if __debug__:' not in line) and (not debugBlock):
data += line
continue
elif 'if __debug__:' in line:
debugBlock = True
indentLevel = thisIndentLevel
continue
if thisIndentLevel <= indentLevel:
if 'else' in line:
elseBlock = True
continue
if 'elif' in line:
line = line[:thisIndentLevel] + line[thisIndentLevel+2:]
data += line
debugBlock = False
elseBlock = False
indentLevel = 0
continue
if elseBlock:
data += line[4:]
return data
for module in args.modules:
print 'Writing module...', module
for root, folders, files in os.walk(os.path.join(args.src_dir, module)):
outputDir = root.replace(args.src_dir, args.build_dir)
if not os.path.exists(outputDir):
os.mkdir(outputDir)
for filename in files:
if filename not in includes:
if not filename.endswith('.py'):
continue
if filename.endswith('UD.py'):
continue
if filename.endswith('AI.py'):
continue
if filename in excludes:
continue
with open(os.path.join(root, filename), 'r') as f:
data = minify(f)
with open(os.path.join(outputDir, filename), 'w') as f:
f.write(data)
# Let's write game_data.py now. game_data.py is a compile-time generated
# collection of data that will be used by the game at runtime. It contains the
# PRC file data, (stripped) DC file, and time zone info.
# First, we need the PRC file data:
configFileName = 'config_{0}.prc'.format(args.distribution)
configData = []
with open(os.path.join(args.src_dir, 'config', configFileName)) as f:
data = f.read()
configData.append(data.replace('SERVER_VERSION', serverVersion))
print 'Using config file: {0}'.format(configFileName)
# Next, we need the (stripped) DC file:
dcFile = DCFile()
filepath = os.path.join(args.src_dir, 'astron')
for filename in os.listdir(filepath):
if filename.endswith('.dc'):
dcFile.read(Filename.fromOsSpecific(os.path.join(filepath, filename)))
dcStream = StringStream()
dcFile.write(dcStream, True)
dcData = dcStream.getData()
# Now, collect our timezone info:
zoneInfo = {}
for timezone in pytz.all_timezones:
zoneInfo['zoneinfo/' + timezone] = pytz.open_resource(timezone).read()
# Finally, write our data to game_data.py:
print 'Writing game_data.py...'
gameData = '''\
CONFIG = %r
DC = %r
ZONEINFO = %r'''
with open(os.path.join(args.build_dir, 'game_data.py'), 'w') as f:
f.write(gameData % (configData, dcData, zoneInfo))
def getDirectoryMD5Hash(directory):
def _updateChecksum(checksum, dirname, filenames):
for filename in sorted(filenames):
path = os.path.join(dirname, filename)
if os.path.isfile(path):
fh = open(path, 'rb')
while True:
buf = fh.read(4096)
if not buf:
break
checksum.update(buf)
fh.close()
checksum = hashlib.md5()
directory = os.path.normpath(directory)
if os.path.exists(directory):
if os.path.isdir(directory):
os.path.walk(directory, _updateChecksum, checksum)
elif os.path.isfile(directory):
_updateChecksum(
checksum, os.path.dirname(directory),
os.path.basename(directory))
return checksum.hexdigest()
# We have all of the code gathered together. Let's create the multifiles now:
if args.build_mfs:
print 'Building multifiles...'
dest = os.path.join(args.build_dir, 'resources')
if not os.path.exists(dest):
os.mkdir(dest)
dest = os.path.realpath(dest)
os.chdir(args.resources_dir)
if not os.path.exists('local-patcher.ver'):
with open('local-patcher.ver', 'w') as f:
f.write('RESOURCES = {}')
with open('local-patcher.ver', 'r') as f:
exec(f.read())
for phase in os.listdir('.'):
if not phase.startswith('phase_'):
continue
if not os.path.isdir(phase):
continue
phaseMd5 = getDirectoryMD5Hash(phase)
if phase in RESOURCES:
if RESOURCES[phase] == phaseMd5:
continue
filename = phase + '.mf'
print 'Writing...', filename
filepath = os.path.join(dest, filename)
os.system('multify -c -f {0} {1}'.format(filepath, phase))
RESOURCES[phase] = phaseMd5
with open('local-patcher.ver', 'w') as f:
f.write('RESOURCES = %r' % RESOURCES)
print 'Done preparing the client.'
Here’s the error code I get:
Traceback (most recent call last):
File "prepare_client.py", line 7, in <module>
from pandac.PandaModules import *
File "C:\Panda3D-1.9.0\pandac\PandaModules.py", line 20, in <module>
from panda3dDirectModules import *
File "C:\Panda3D-1.9.0\pandac\panda3dDirectModules.py", line 5, in <module>
from direct.directnotify.DirectNotifyGlobal import directNotify
ImportError: No module named directnotify.DirectNotifyGlobal
Panda3D-1.9.0/direct/directnotify/DirectNotifyGlobal.py exists… I do not understand the error.
When trying build:
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument('--panda3d-dir', default='C:/Panda3D-1.9.0',
help='The path to the Panda3D build to use for this distribution.')
parser.add_argument('--main-module', default='infinite.base.ClientStartDist',
help='The path to the instantiation module.')
parser.add_argument('--build-secret', default='dev',
help='The secret that will be used to encrypt the build.')
parser.add_argument('modules', nargs='*', default=['shared', 'infinite'],
help='The Toontown modules to be included in the build.')
args = parser.parse_args()
print 'Building the client...'
os.chdir('build')
cmd = os.path.join(args.panda3d_dir, 'python/ppython.exe') # ppython
cmd += ' -m direct.showutil.pfreeze' # pfreeze
args.modules.extend(['direct', 'pandac'])
for module in args.modules:
cmd += ' -i {0}.*.*'.format(module)
cmd += ' -i {0}.*'.format('encodings')
cmd += ' -i {0}'.format('base64')
cmd += ' -i {0}'.format('site')
cmd += ' -o GameData.pyd' # The filename of the built *.PYD.
cmd += ' {0}'.format(args.main_module) # "main" module
os.system(cmd)
print 'Done building the client.'
I get this error:
Building the client...
Traceback (most recent call last):
File "build_client.py", line 18, in <module>
os.chdir('build')
WindowsError: [Error 2] The system cannot find the file specified: 'build'
build.py is in my Panda3D-1.9.0/python/lib directory, and exists. I do not understand the issue. It seems like the Python path is wrong?
Any pointers would be useful. Thanks.