def buildDmg(startDir): fstartDir = Filename.fromOsSpecific(startDir) rootFilename = Filename(fstartDir, 'bundle') output = Filename(fstartDir, 'nppanda3d.dmg') output.unlink() cmd = 'hdiutil create -fs HFS+ -srcfolder "%(dir)s" -volname "%(volname)s" "%(output)s"' % { 'dir': rootFilename.toOsSpecific(), 'volname': 'nppanda3d', 'output': output.toOsSpecific(), } os.system(cmd)
def buildDmg(startDir): fstartDir = Filename.fromOsSpecific(startDir) rootFilename = Filename(fstartDir, 'bundle') output = Filename(fstartDir, 'nppanda3d.dmg') output.unlink() cmd = 'hdiutil create -fs HFS+ -srcfolder "%(dir)s" -volname "%(volname)s" "%(output)s"' % { 'dir' : rootFilename.toOsSpecific(), 'volname' : 'nppanda3d', 'output' : output.toOsSpecific(), } os.system(cmd)
def _compile(self, filename, source): """ Compiles the Python source code to a code object and attempts to write it to an appropriate .pyc file. May raise SyntaxError or other errors generated by the compiler. """ if source and source[-1] != '\n': source = source + '\n' code = __builtin__.compile(source, filename.toOsSpecific(), 'exec') # try to cache the compiled code pycFilename = Filename(filename) pycFilename.setExtension(compiledExtensions[0]) try: f = open(pycFilename.toOsSpecific(), 'wb') except IOError: pass else: f.write('\0\0\0\0') f.write( chr(self.timestamp & 0xff) + chr((self.timestamp >> 8) & 0xff) + chr((self.timestamp >> 16) & 0xff) + chr((self.timestamp >> 24) & 0xff)) f.write(marshal.dumps(code)) f.flush() f.seek(0, 0) f.write(imp.get_magic()) f.close() return code
def _compile(self, filename, source): """ Compiles the Python source code to a code object and attempts to write it to an appropriate .pyc file. May raise SyntaxError or other errors generated by the compiler. """ if source and source[-1] != "\n": source = source + "\n" code = compile(source, filename.toOsSpecific(), "exec") # try to cache the compiled code pycFilename = Filename(filename) pycFilename.setExtension(compiledExtensions[0]) try: f = open(pycFilename.toOsSpecific(), "wb") except IOError: pass else: f.write(imp.get_magic()) if sys.version_info >= (3, 0): f.write((self.timestamp & 0xFFFFFFFF).to_bytes(4, "little")) f.write(b"\0\0\0\0") else: f.write( chr(self.timestamp & 0xFF) + chr((self.timestamp >> 8) & 0xFF) + chr((self.timestamp >> 16) & 0xFF) + chr((self.timestamp >> 24) & 0xFF) ) f.write(marshal.dumps(code)) f.close() return code
def saveNewsCache(self): cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename) try: file = open(cacheIndexFilename.toOsSpecific(), 'w') except IOError, e: self.notify.warning('error opening news cache file %s: %s' % (cacheIndexFilename, str(e))) return
def appendColorToColorPaletteFile(color): obj = base.le.DNATarget if obj: classType = DNAGetClassType(obj) if classType == DNA_WALL: tag = 'wall_color:' elif classType == DNA_WINDOWS: tag = 'window_color:' elif classType == DNA_DOOR: tag = 'door_color:' elif classType == DNA_FLAT_DOOR: tag = 'door_color:' elif classType == DNA_CORNICE: tag = 'cornice_color:' elif classType == DNA_PROP: tag = 'prop_color:' else: return # Valid type, add color to file filename = base.le.neighborhood + '_colors.txt' fname = Filename(dnaDirectory.getFullpath() + '/stylefiles/' + filename) f = open(fname.toOsSpecific(), 'ab') f.write( '%s Vec4(%.2f, %.2f, %.2f, 1.0)\n' % (tag, color[0] / 255.0, color[1] / 255.0, color[2] / 255.0)) f.close()
def _compile(self, filename, source): """ Compiles the Python source code to a code object and attempts to write it to an appropriate .pyc file. May raise SyntaxError or other errors generated by the compiler. """ if source and source[-1] != '\n': source = source + '\n' code = __builtin__.compile(source, filename.toOsSpecific(), 'exec') # try to cache the compiled code pycFilename = Filename(filename) pycFilename.setExtension(compiledExtensions[0]) try: f = open(pycFilename.toOsSpecific(), 'wb') except IOError: pass else: f.write('\0\0\0\0') f.write(chr(self.timestamp & 0xff) + chr((self.timestamp >> 8) & 0xff) + chr((self.timestamp >> 16) & 0xff) + chr((self.timestamp >> 24) & 0xff)) f.write(marshal.dumps(code)) f.flush() f.seek(0, 0) f.write(imp.get_magic()) f.close() return code
def __uncompressArchive(self, step): """ Turns the compressed archive into the uncompressed archive. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # We're not allowed to! yield self.stepFailed return self.updated = True sourcePathname = Filename(self.getPackageDir(), self.compressedArchive.filename) targetPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) targetPathname.unlink() self.notify.info("Uncompressing %s to %s" % (sourcePathname, targetPathname)) decompressor = Decompressor() decompressor.initiate(sourcePathname, targetPathname) totalBytes = self.uncompressedArchive.size result = decompressor.run() while result == EUOk: step.bytesDone = int(totalBytes * decompressor.getProgress()) self.__updateStepProgress(step) result = decompressor.run() if taskMgr.destroyed: # If the task manager has been destroyed, we must # be shutting down. Get out of here. self.notify.warning( "Task Manager destroyed, aborting decompresss %s" % (sourcePathname)) yield self.stepFailed return yield self.stepContinue if result != EUSuccess: yield self.stepFailed return step.bytesDone = totalBytes self.__updateStepProgress(step) if not self.uncompressedArchive.quickVerify(self.getPackageDir(), notify=self.notify): self.notify.warning("after uncompressing, %s still incorrect" % (self.uncompressedArchive.filename)) yield self.stepFailed return # Now that we've verified the archive, make it read-only. os.chmod(targetPathname.toOsSpecific(), 0o444) # Now we can safely remove the compressed archive. sourcePathname.unlink() yield self.stepComplete return
def downloadDescFileGenerator(self, http): """ A generator function that implements downloadDescFile() one piece at a time. It yields one of stepComplete, stepFailed, or stepContinue. """ assert self.descFile if self.hasDescFile: # We've already got one. yield self.stepComplete; return if not self.host.appRunner or self.host.appRunner.verifyContents != self.host.appRunner.P3DVCNever: # We're allowed to download it. self.http = http func = lambda step, self = self: self.__downloadFile( None, self.descFile, urlbase = self.descFile.filename, filename = self.descFileBasename) step = self.InstallStep(func, self.descFile.size, self.downloadFactor, 'downloadDesc') for token in step.func(): if token == self.stepContinue: yield token else: break while token == self.restartDownload: # Try again. func = lambda step, self = self: self.__downloadFile( None, self.descFile, urlbase = self.descFile.filename, filename = self.descFileBasename) step = self.InstallStep(func, self.descFile.size, self.downloadFactor, 'downloadDesc') for token in step.func(): if token == self.stepContinue: yield token else: break if token == self.stepFailed: # Couldn't download the desc file. yield self.stepFailed; return assert token == self.stepComplete filename = Filename(self.getPackageDir(), self.descFileBasename) # Now that we've written the desc file, make it read-only. os.chmod(filename.toOsSpecific(), 0o444) if not self.__readDescFile(): # Weird, it passed the hash check, but we still can't read # it. filename = Filename(self.getPackageDir(), self.descFileBasename) self.notify.warning("Failure reading %s" % (filename)) yield self.stepFailed; return yield self.stepComplete; return
def __init__(self, pathname, ignoreUsageXml=False): self.pathname = pathname self.filenames = [] self.fileSize = 0 self.nested = [] self.nestedSize = 0 xusage = None if not ignoreUsageXml: # Look for a usage.xml file in this directory. If we find # one, we read it for the file size and then stop here, as # an optimization. usageFilename = Filename(pathname, 'usage.xml') doc = TiXmlDocument(usageFilename.toOsSpecific()) if doc.LoadFile(): xusage = doc.FirstChildElement('usage') if xusage: diskSpace = xusage.Attribute('disk_space') try: diskSpace = int(diskSpace or '') except ValueError: diskSpace = None if diskSpace is not None: self.fileSize = diskSpace return files = vfs.scanDirectory(self.pathname) if files is None: files = [] for vfile in files: if hasattr(vfile, 'getMount'): if not isinstance(vfile.getMount(), VirtualFileMountSystem): # Not a real file; ignore it. continue if vfile.isDirectory(): # A nested directory. subdir = ScanDirectoryNode(vfile.getFilename(), ignoreUsageXml=ignoreUsageXml) self.nested.append(subdir) self.nestedSize += subdir.getTotalSize() elif vfile.isRegularFile(): # A nested file. self.filenames.append(vfile.getFilename()) self.fileSize += vfile.getFileSize() else: # Some other wacky file thing. self.filenames.append(vfile.getFilename()) if xusage: # Now update the usage.xml file with the newly-determined # disk space. xusage.SetAttribute('disk_space', str(self.getTotalSize())) tfile = Filename.temporary(str(pathname), '.xml') if doc.SaveFile(tfile.toOsSpecific()): tfile.renameTo(usageFilename)
def downloadDescFileGenerator(self, http): """ A generator function that implements downloadDescFile() one piece at a time. It yields one of stepComplete, stepFailed, or stepContinue. """ assert self.descFile if self.hasDescFile: # We've already got one. yield self.stepComplete; return if self.host.appRunner and self.host.appRunner.verifyContents != self.host.appRunner.P3DVCNever: # We're allowed to download it. self.http = http func = lambda step, self = self: self.__downloadFile( None, self.descFile, urlbase = self.descFile.filename, filename = self.descFileBasename) step = self.InstallStep(func, self.descFile.size, self.downloadFactor, 'downloadDesc') for token in step.func(): if token == self.stepContinue: yield token else: break while token == self.restartDownload: # Try again. func = lambda step, self = self: self.__downloadFile( None, self.descFile, urlbase = self.descFile.filename, filename = self.descFileBasename) step = self.InstallStep(func, self.descFile.size, self.downloadFactor, 'downloadDesc') for token in step.func(): if token == self.stepContinue: yield token else: break if token == self.stepFailed: # Couldn't download the desc file. yield self.stepFailed; return assert token == self.stepComplete filename = Filename(self.getPackageDir(), self.descFileBasename) # Now that we've written the desc file, make it read-only. os.chmod(filename.toOsSpecific(), 0o444) if not self.__readDescFile(): # Weird, it passed the hash check, but we still can't read # it. filename = Filename(self.getPackageDir(), self.descFileBasename) self.notify.warning("Failure reading %s" % (filename)) yield self.stepFailed; return yield self.stepComplete; return
def makeBundle(startDir): fstartDir = Filename.fromOsSpecific(startDir) # Search for nppandad along $DYLD_LIBRARY_PATH. path = DSearchPath() if 'LD_LIBRARY_PATH' in os.environ: path.appendPath(os.environ['LD_LIBRARY_PATH']) if 'DYLD_LIBRARY_PATH' in os.environ: path.appendPath(os.environ['DYLD_LIBRARY_PATH']) nppanda3d = path.findFile('nppanda3d') if not nppanda3d: raise Exception("Couldn't find nppanda3d on path.") # Generate the bundle directory structure rootFilename = Filename(fstartDir, 'bundle') if os.path.exists(rootFilename.toOsSpecific()): shutil.rmtree(rootFilename.toOsSpecific()) bundleFilename = Filename(rootFilename, 'nppanda3d.plugin') plistFilename = Filename(bundleFilename, 'Contents/Info.plist') plistFilename.makeDir() exeFilename = Filename(bundleFilename, 'Contents/MacOS/nppanda3d') exeFilename.makeDir() resourceFilename = Filename(bundleFilename, 'Contents/Resources/nppanda3d.rsrc') resourceFilename.makeDir() # Compile the .r file to an .rsrc file. os.system('/Developer/Tools/Rez -useDF -o %s %s' % (resourceFilename.toOsSpecific(), Filename(fstartDir, "nppanda3d.r").toOsSpecific())) if not resourceFilename.exists(): raise IOError('Unable to run Rez') # Copy in Info.plist and the compiled executable. shutil.copyfile( Filename(fstartDir, "nppanda3d.plist").toOsSpecific(), plistFilename.toOsSpecific()) shutil.copyfile(nppanda3d.toOsSpecific(), exeFilename.toOsSpecific()) # All done! bundleFilename.touch() print(bundleFilename.toOsSpecific())
def __init__(self, pathname, ignoreUsageXml = False): self.pathname = pathname self.filenames = [] self.fileSize = 0 self.nested = [] self.nestedSize = 0 xusage = None if not ignoreUsageXml: # Look for a usage.xml file in this directory. If we find # one, we read it for the file size and then stop here, as # an optimization. usageFilename = Filename(pathname, 'usage.xml') doc = TiXmlDocument(usageFilename.toOsSpecific()) if doc.LoadFile(): xusage = doc.FirstChildElement('usage') if xusage: diskSpace = xusage.Attribute('disk_space') try: diskSpace = int(diskSpace or '') except ValueError: diskSpace = None if diskSpace is not None: self.fileSize = diskSpace return files = vfs.scanDirectory(self.pathname) if files is None: files = [] for vfile in files: if hasattr(vfile, 'getMount'): if not isinstance(vfile.getMount(), VirtualFileMountSystem): # Not a real file; ignore it. continue if vfile.isDirectory(): # A nested directory. subdir = ScanDirectoryNode(vfile.getFilename(), ignoreUsageXml = ignoreUsageXml) self.nested.append(subdir) self.nestedSize += subdir.getTotalSize() elif vfile.isRegularFile(): # A nested file. self.filenames.append(vfile.getFilename()) self.fileSize += vfile.getFileSize() else: # Some other wacky file thing. self.filenames.append(vfile.getFilename()) if xusage: # Now update the usage.xml file with the newly-determined # disk space. xusage.SetAttribute('disk_space', str(self.getTotalSize())) tfile = Filename.temporary(str(pathname), '.xml') if doc.SaveFile(tfile.toOsSpecific()): tfile.renameTo(usageFilename)
def saveNewsCache(self): cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename) try: file = open(cacheIndexFilename.toOsSpecific(), 'w') except IOError as e: self.notify.warning('error opening news cache file %s: %s' % (cacheIndexFilename, str(e))) return for filename, (size, date) in self.newsCache.items(): print >> file, '%s\t%s\t%s' % (filename, size, date)
def makeBundle(startDir): fstartDir = Filename.fromOsSpecific(startDir) # Search for nppandad along $DYLD_LIBRARY_PATH. path = DSearchPath() if 'LD_LIBRARY_PATH' in os.environ: path.appendPath(os.environ['LD_LIBRARY_PATH']) if 'DYLD_LIBRARY_PATH' in os.environ: path.appendPath(os.environ['DYLD_LIBRARY_PATH']) nppanda3d = path.findFile('nppanda3d') if not nppanda3d: raise Exception("Couldn't find nppanda3d on path.") # Generate the bundle directory structure rootFilename = Filename(fstartDir, 'bundle') if os.path.exists(rootFilename.toOsSpecific()): shutil.rmtree(rootFilename.toOsSpecific()) bundleFilename = Filename(rootFilename, 'nppanda3d.plugin') plistFilename = Filename(bundleFilename, 'Contents/Info.plist') plistFilename.makeDir() exeFilename = Filename(bundleFilename, 'Contents/MacOS/nppanda3d') exeFilename.makeDir() resourceFilename = Filename(bundleFilename, 'Contents/Resources/nppanda3d.rsrc') resourceFilename.makeDir() # Compile the .r file to an .rsrc file. os.system('/Developer/Tools/Rez -useDF -o %s %s' % ( resourceFilename.toOsSpecific(), Filename(fstartDir, "nppanda3d.r").toOsSpecific())) if not resourceFilename.exists(): raise IOError('Unable to run Rez') # Copy in Info.plist and the compiled executable. shutil.copyfile(Filename(fstartDir, "nppanda3d.plist").toOsSpecific(), plistFilename.toOsSpecific()) shutil.copyfile(nppanda3d.toOsSpecific(), exeFilename.toOsSpecific()) # All done! bundleFilename.touch() print(bundleFilename.toOsSpecific())
def makeBundle(startDir): fstartDir = Filename.fromOsSpecific(startDir) # Search for panda3d_mac along $PATH. path = DSearchPath() if 'PATH' in os.environ: path.appendPath(os.environ['PATH']) path.appendPath(os.defpath) panda3d_mac = path.findFile('panda3d_mac') if not panda3d_mac: raise Exception("Couldn't find panda3d_mac on path.") # Construct a search path to look for the images. search = DSearchPath() # First on the path: an explicit $PLUGIN_IMAGES env var. if ExecutionEnvironment.hasEnvironmentVariable('PLUGIN_IMAGES'): search.appendDirectory(Filename.expandFrom('$PLUGIN_IMAGES')) # Next on the path: the models/plugin_images directory within the # current directory. search.appendDirectory('models/plugin_images') # Finally on the path: models/plugin_images within the model # search path. for dir in getModelPath().getDirectories(): search.appendDirectory(Filename(dir, 'plugin_images')) # Now find the icon file on the above search path. icons = search.findFile('panda3d.icns') if not icons: raise Exception("Couldn't find panda3d.icns on model-path.") # Generate the bundle directory structure rootFilename = Filename(fstartDir) bundleFilename = Filename(rootFilename, 'Panda3D.app') if os.path.exists(bundleFilename.toOsSpecific()): shutil.rmtree(bundleFilename.toOsSpecific()) plistFilename = Filename(bundleFilename, 'Contents/Info.plist') plistFilename.makeDir() exeFilename = Filename(bundleFilename, 'Contents/MacOS/panda3d_mac') exeFilename.makeDir() iconFilename = Filename(bundleFilename, 'Contents/Resources/panda3d.icns') iconFilename.makeDir() # Copy in Info.plist, the icon file, and the compiled executable. shutil.copyfile( Filename(fstartDir, "panda3d_mac.plist").toOsSpecific(), plistFilename.toOsSpecific()) shutil.copyfile(icons.toOsSpecific(), iconFilename.toOsSpecific()) print('%s %s' % (panda3d_mac, exeFilename)) shutil.copyfile(panda3d_mac.toOsSpecific(), exeFilename.toOsSpecific()) os.chmod(exeFilename.toOsSpecific(), 0o755) # All done! bundleFilename.touch() print(bundleFilename.toOsSpecific())
def saveStyle(filename, style): # A generic routine to append a new style definition to one of # the style files. fname = Filename(dnaDirectory.getFullpath() + '/stylefiles/' + filename) # We use binary mode to avoid Windows' end-of-line convention f = open(fname.toOsSpecific(), 'a') # Add a blank line f.write('\n') # Now output style details to file style.output(f) # Close the file f.close()
def makeBundle(startDir): fstartDir = Filename.fromOsSpecific(startDir) # Search for panda3d_mac along $PATH. path = DSearchPath() if 'PATH' in os.environ: path.appendPath(os.environ['PATH']) path.appendPath(os.defpath) panda3d_mac = path.findFile('panda3d_mac') if not panda3d_mac: raise Exception("Couldn't find panda3d_mac on path.") # Construct a search path to look for the images. search = DSearchPath() # First on the path: an explicit $PLUGIN_IMAGES env var. if ExecutionEnvironment.hasEnvironmentVariable('PLUGIN_IMAGES'): search.appendDirectory(Filename.expandFrom('$PLUGIN_IMAGES')) # Next on the path: the models/plugin_images directory within the # current directory. search.appendDirectory('models/plugin_images') # Finally on the path: models/plugin_images within the model # search path. for dir in getModelPath().getDirectories(): search.appendDirectory(Filename(dir, 'plugin_images')) # Now find the icon file on the above search path. icons = search.findFile('panda3d.icns') if not icons: raise Exception("Couldn't find panda3d.icns on model-path.") # Generate the bundle directory structure rootFilename = Filename(fstartDir) bundleFilename = Filename(rootFilename, 'Panda3D.app') if os.path.exists(bundleFilename.toOsSpecific()): shutil.rmtree(bundleFilename.toOsSpecific()) plistFilename = Filename(bundleFilename, 'Contents/Info.plist') plistFilename.makeDir() exeFilename = Filename(bundleFilename, 'Contents/MacOS/panda3d_mac') exeFilename.makeDir() iconFilename = Filename(bundleFilename, 'Contents/Resources/panda3d.icns') iconFilename.makeDir() # Copy in Info.plist, the icon file, and the compiled executable. shutil.copyfile(Filename(fstartDir, "panda3d_mac.plist").toOsSpecific(), plistFilename.toOsSpecific()) shutil.copyfile(icons.toOsSpecific(), iconFilename.toOsSpecific()) print('%s %s' % (panda3d_mac, exeFilename)) shutil.copyfile(panda3d_mac.toOsSpecific(), exeFilename.toOsSpecific()) os.chmod(exeFilename.toOsSpecific(), 0o755) # All done! bundleFilename.touch() print(bundleFilename.toOsSpecific())
def __uncompressArchive(self, step): """ Turns the compressed archive into the uncompressed archive. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # We're not allowed to! yield self.stepFailed; return self.updated = True sourcePathname = Filename(self.getPackageDir(), self.compressedArchive.filename) targetPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) targetPathname.unlink() self.notify.info("Uncompressing %s to %s" % (sourcePathname, targetPathname)) decompressor = Decompressor() decompressor.initiate(sourcePathname, targetPathname) totalBytes = self.uncompressedArchive.size result = decompressor.run() while result == EUOk: step.bytesDone = int(totalBytes * decompressor.getProgress()) self.__updateStepProgress(step) result = decompressor.run() if taskMgr.destroyed: # If the task manager has been destroyed, we must # be shutting down. Get out of here. self.notify.warning("Task Manager destroyed, aborting decompresss %s" % (sourcePathname)) yield self.stepFailed; return yield self.stepContinue if result != EUSuccess: yield self.stepFailed; return step.bytesDone = totalBytes self.__updateStepProgress(step) if not self.uncompressedArchive.quickVerify(self.getPackageDir(), notify= self.notify): self.notify.warning("after uncompressing, %s still incorrect" % ( self.uncompressedArchive.filename)) yield self.stepFailed; return # Now that we've verified the archive, make it read-only. os.chmod(targetPathname.toOsSpecific(), 0o444) # Now we can safely remove the compressed archive. sourcePathname.unlink() yield self.stepComplete; return
def getUsage(self): """ Returns the xusage element that is read from the usage.xml file, or None if there is no usage.xml file. """ if not hasattr(core, 'TiXmlDocument'): return None filename = Filename(self.getPackageDir(), self.UsageBasename) doc = TiXmlDocument(filename.toOsSpecific()) if not doc.LoadFile(): return None xusage = doc.FirstChildElement('usage') if not xusage: return None return copy.copy(xusage)
def readNewsCache(self): cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename) self.newsCache = {} if cacheIndexFilename.isRegularFile(): file = open(cacheIndexFilename.toOsSpecific(), 'r') for line in file.readlines(): line = line.strip() keywords = line.split('\t') if len(keywords) == 3: filename, size, date = keywords if filename in self.newsFiles: try: size = int(size) except ValueError: size = 0 self.newsCache[filename] = (size, date)
def readConfigXml(self): """ Reads the config.xml file that may be present in the root directory. """ if not hasattr(core, 'TiXmlDocument'): return filename = Filename(self.rootDir, self.ConfigBasename) doc = core.TiXmlDocument(filename.toOsSpecific()) if not doc.LoadFile(): return xconfig = doc.FirstChildElement('config') if xconfig: maxDiskUsage = xconfig.Attribute('max_disk_usage') try: self.maxDiskUsage = int(maxDiskUsage or '') except ValueError: pass
def fromFile(self, packageDir, filename, pathname = None, st = None): """ Reads the file information from the indicated file. If st is supplied, it is the result of os.stat on the filename. """ vfs = VirtualFileSystem.getGlobalPtr() filename = Filename(filename) if pathname is None: pathname = Filename(packageDir, filename) self.filename = str(filename) self.basename = filename.getBasename() if st is None: st = os.stat(pathname.toOsSpecific()) self.size = st.st_size self.timestamp = int(st.st_mtime) self.readHash(pathname)
def fromFile(self, packageDir, filename, pathname=None, st=None): """ Reads the file information from the indicated file. If st is supplied, it is the result of os.stat on the filename. """ vfs = VirtualFileSystem.getGlobalPtr() filename = Filename(filename) if pathname is None: pathname = Filename(packageDir, filename) self.filename = filename.cStr() self.basename = filename.getBasename() if st is None: st = os.stat(pathname.toOsSpecific()) self.size = st.st_size self.timestamp = st.st_mtime self.readHash(pathname)
def fullVerify(self, packageDir=None, pathname=None, notify=None): """ Performs a more thorough test to ensure the file has not been modified. This test is less vulnerable to malicious attacks, since it reads and verifies the entire file. Returns true if it is intact, false if it needs to be redownloaded. """ if not pathname: pathname = Filename(packageDir, self.filename) try: st = os.stat(pathname.toOsSpecific()) except OSError: # If the file is missing, the file fails. if notify: notify.debug("file not found: %s" % (pathname)) return False if st.st_size != self.size: # If the size is wrong, the file fails; if notify: notify.debug("size wrong: %s" % (pathname)) return False if not self.checkHash(packageDir, pathname, st): # Hard fail, the hash is wrong. if notify: notify.debug("hash check wrong: %s" % (pathname)) notify.debug(" found %s, expected %s" % (self.actualFile.hash, self.hash)) return False if notify: notify.debug("hash check ok: %s" % (pathname)) # The hash is OK. If the timestamp is wrong, change it back # to what we expect it to be, so we can quick-verify it # successfully next time. if st.st_mtime != self.timestamp: self.__updateTimestamp(pathname, st) return True
def fullVerify(self, packageDir = None, pathname = None, notify = None): """ Performs a more thorough test to ensure the file has not been modified. This test is less vulnerable to malicious attacks, since it reads and verifies the entire file. Returns true if it is intact, false if it needs to be redownloaded. """ if not pathname: pathname = Filename(packageDir, self.filename) try: st = os.stat(pathname.toOsSpecific()) except OSError: # If the file is missing, the file fails. if notify: notify.debug("file not found: %s" % (pathname)) return False if st.st_size != self.size: # If the size is wrong, the file fails; if notify: notify.debug("size wrong: %s" % (pathname)) return False if not self.checkHash(packageDir, pathname, st): # Hard fail, the hash is wrong. if notify: notify.debug("hash check wrong: %s" % (pathname)) notify.debug(" found %s, expected %s" % (self.actualFile.hash, self.hash)) return False if notify: notify.debug("hash check ok: %s" % (pathname)) # The hash is OK. If the timestamp is wrong, change it back # to what we expect it to be, so we can quick-verify it # successfully next time. if int(st.st_mtime) != self.timestamp: self.__updateTimestamp(pathname, st) return True
def writeConfigXml(self): """ Rewrites the config.xml to the root directory. This isn't called automatically; an application may call this after adjusting some parameters (such as self.maxDiskUsage). """ from panda3d.core import TiXmlDocument, TiXmlDeclaration, TiXmlElement filename = Filename(self.rootDir, self.ConfigBasename) doc = TiXmlDocument(filename.toOsSpecific()) decl = TiXmlDeclaration("1.0", "utf-8", "") doc.InsertEndChild(decl) xconfig = TiXmlElement('config') xconfig.SetAttribute('max_disk_usage', str(self.maxDiskUsage)) doc.InsertEndChild(xconfig) # Write the file to a temporary filename, then atomically move # it to its actual filename, to avoid race conditions when # updating this file. tfile = Filename.temporary(str(self.rootDir), '.xml') if doc.SaveFile(tfile.toOsSpecific()): tfile.renameTo(filename)
def loadFGDFiles(self): """Reads the .fgd files specified in the config file""" self.fgd = Fgd() numVals = LEConfig.fgd_files.getNumUniqueValues() if numVals == 0: QtWidgets.QMessageBox.critical( None, LEGlobals.AppName, "No FGD files specified in local config!", QtWidgets.QMessageBox.Ok) sys.exit(1) vfs = VirtualFileSystem.getGlobalPtr() searchPath = getModelPath().getValue() for i in range(numVals): fgdFilename = LEConfig.fgd_files.getUniqueValue(i) fgdFilename = ExecutionEnvironment.expandString(fgdFilename) fgdFilename = Filename(fgdFilename) vfs.resolveFilename(fgdFilename, searchPath) fgd = FgdParse(fgdFilename.toOsSpecific()) self.fgd.add_include(fgd)
def readContentsFile(self, tempFilename = None, freshDownload = False): """ Reads the contents.xml file for this particular host, once it has been downloaded into the indicated temporary file. Returns true on success, false if the contents file is not already on disk or is unreadable. If tempFilename is specified, it is the filename read, and it is copied the file into the standard location if it's not there already. If tempFilename is not specified, the standard filename is read if it is known. """ if not hasattr(core, 'TiXmlDocument'): return False if not tempFilename: if self.hostDir: # If the filename is not specified, we can infer it # if we already know our hostDir hostDir = self.hostDir else: # Otherwise, we have to guess the hostDir. hostDir = self.__determineHostDir(None, self.hostUrl) tempFilename = Filename(hostDir, 'contents.xml') doc = core.TiXmlDocument(tempFilename.toOsSpecific()) if not doc.LoadFile(): return False xcontents = doc.FirstChildElement('contents') if not xcontents: return False maxAge = xcontents.Attribute('max_age') if maxAge: try: maxAge = int(maxAge) except: maxAge = None if maxAge is None: # Default max_age if unspecified (see p3d_plugin.h). from direct.p3d.AppRunner import AppRunner maxAge = AppRunner.P3D_CONTENTS_DEFAULT_MAX_AGE # Get the latest possible expiration time, based on the max_age # indication. Any expiration time later than this is in error. now = int(time.time()) self.contentsExpiration = now + maxAge if freshDownload: self.contentsSpec.readHash(tempFilename) # Update the XML with the new download information. xorig = xcontents.FirstChildElement('orig') while xorig: xcontents.RemoveChild(xorig) xorig = xcontents.FirstChildElement('orig') xorig = core.TiXmlElement('orig') self.contentsSpec.storeXml(xorig) xorig.SetAttribute('expiration', str(self.contentsExpiration)) xcontents.InsertEndChild(xorig) else: # Read the download hash and expiration time from the XML. expiration = None xorig = xcontents.FirstChildElement('orig') if xorig: self.contentsSpec.loadXml(xorig) expiration = xorig.Attribute('expiration') if expiration: try: expiration = int(expiration) except: expiration = None if not self.contentsSpec.hash: self.contentsSpec.readHash(tempFilename) if expiration is not None: self.contentsExpiration = min(self.contentsExpiration, expiration) # Look for our own entry in the hosts table. if self.hostUrl: self.__findHostXml(xcontents) else: assert self.hostDir self.__findHostXmlForHostDir(xcontents) if self.rootDir and not self.hostDir: self.hostDir = self.__determineHostDir(None, self.hostUrl) # Get the list of packages available for download and/or import. xpackage = xcontents.FirstChildElement('package') while xpackage: name = xpackage.Attribute('name') platform = xpackage.Attribute('platform') version = xpackage.Attribute('version') try: solo = int(xpackage.Attribute('solo') or '') except ValueError: solo = False try: perPlatform = int(xpackage.Attribute('per_platform') or '') except ValueError: perPlatform = False package = self.__makePackage(name, platform, version, solo, perPlatform) package.descFile = FileSpec() package.descFile.loadXml(xpackage) package.setupFilenames() package.importDescFile = None ximport = xpackage.FirstChildElement('import') if ximport: package.importDescFile = FileSpec() package.importDescFile.loadXml(ximport) xpackage = xpackage.NextSiblingElement('package') self.hasContentsFile = True # Now save the contents.xml file into the standard location. if self.appRunner and self.appRunner.verifyContents != self.appRunner.P3DVCNever: assert self.hostDir filename = Filename(self.hostDir, 'contents.xml') filename.makeDir() if freshDownload: doc.SaveFile(filename.toOsSpecific()) else: if filename != tempFilename: tempFilename.copyTo(filename) return True
def markUsed(self): """ Marks the package as having been used. This is normally called automatically by installPackage(). """ if not hasattr(core, 'TiXmlDocument'): return if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # Not allowed to write any files to the package directory. return if self.updated: # If we've just installed a new version of the package, # re-measure the actual disk space used. self.diskSpace = self.__measureDiskSpace() filename = Filename(self.getPackageDir(), self.UsageBasename) doc = TiXmlDocument(filename.toOsSpecific()) if not doc.LoadFile(): decl = TiXmlDeclaration("1.0", "utf-8", "") doc.InsertEndChild(decl) xusage = doc.FirstChildElement('usage') if not xusage: doc.InsertEndChild(TiXmlElement('usage')) xusage = doc.FirstChildElement('usage') now = int(time.time()) count = xusage.Attribute('count_app') try: count = int(count or '') except ValueError: count = 0 xusage.SetAttribute('first_use', str(now)) count += 1 xusage.SetAttribute('count_app', str(count)) xusage.SetAttribute('last_use', str(now)) if self.updated: xusage.SetAttribute('last_update', str(now)) self.updated = False else: # Since we haven't changed the disk space, we can just # read it from the previous xml file. diskSpace = xusage.Attribute('disk_space') try: diskSpace = int(diskSpace or '') except ValueError: # Unless it wasn't set already. self.diskSpace = self.__measureDiskSpace() xusage.SetAttribute('disk_space', str(self.diskSpace)) # Write the file to a temporary filename, then atomically move # it to its actual filename, to avoid race conditions when # updating this file. tfile = Filename.temporary(str(self.getPackageDir()), '.xml') if doc.SaveFile(tfile.toOsSpecific()): tfile.renameTo(filename)
def __readDescFile(self): """ Reads the desc xml file for this particular package, assuming it's been already downloaded and verified. Returns true on success, false on failure. """ if self.hasDescFile: # No need to read it again. return True if self.solo: # If this is a "solo" package, we don't actually "read" # the desc file; that's the entire contents of the # package. self.hasDescFile = True self.hasPackage = True return True filename = Filename(self.getPackageDir(), self.descFileBasename) if not hasattr(core, 'TiXmlDocument'): return False doc = core.TiXmlDocument(filename.toOsSpecific()) if not doc.LoadFile(): return False xpackage = doc.FirstChildElement('package') if not xpackage: return False try: self.patchVersion = int(xpackage.Attribute('patch_version') or '') except ValueError: self.patchVersion = None try: perPlatform = int(xpackage.Attribute('per_platform') or '') except ValueError: perPlatform = False if perPlatform != self.perPlatform: self.notify.warning("per_platform disagreement on package %s" % (self.packageName)) self.displayName = None xconfig = xpackage.FirstChildElement('config') if xconfig: # The name for display to an English-speaking user. self.displayName = xconfig.Attribute('display_name') # True if any apps that use this package must be GUI apps. guiApp = xconfig.Attribute('gui_app') if guiApp: self.guiApp = int(guiApp) # The uncompressed archive, which will be mounted directly, # and also used for patching. xuncompressedArchive = xpackage.FirstChildElement('uncompressed_archive') if xuncompressedArchive: self.uncompressedArchive = FileSpec() self.uncompressedArchive.loadXml(xuncompressedArchive) # The compressed archive, which is what is downloaded. xcompressedArchive = xpackage.FirstChildElement('compressed_archive') if xcompressedArchive: self.compressedArchive = FileSpec() self.compressedArchive.loadXml(xcompressedArchive) # The list of files that should be extracted to disk. self.extracts = [] xextract = xpackage.FirstChildElement('extract') while xextract: file = FileSpec() file.loadXml(xextract) self.extracts.append(file) xextract = xextract.NextSiblingElement('extract') # The list of additional packages that must be installed for # this package to function properly. self.requires = [] xrequires = xpackage.FirstChildElement('requires') while xrequires: packageName = xrequires.Attribute('name') version = xrequires.Attribute('version') hostUrl = xrequires.Attribute('host') if packageName and hostUrl: host = self.host.appRunner.getHostWithAlt(hostUrl) self.requires.append((packageName, version, host)) xrequires = xrequires.NextSiblingElement('requires') self.hasDescFile = True # Now that we've read the desc file, go ahead and use it to # verify the download status. if self.__checkArchiveStatus(): # It's all fully downloaded, unpacked, and ready. self.hasPackage = True return True # Still have to download it. self.__buildInstallPlans() return True
def __downloadFile(self, step, fileSpec, urlbase = None, filename = None, allowPartial = False): """ Downloads the indicated file from the host into packageDir. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # We're not allowed to download anything. yield self.stepFailed; return self.updated = True if not urlbase: urlbase = self.descFileDirname + '/' + fileSpec.filename # Build up a list of URL's to try downloading from. Unlike # the C++ implementation in P3DPackage.cxx, here we build the # URL's in forward order. tryUrls = [] if self.host.appRunner and self.host.appRunner.superMirrorUrl: # We start with the "super mirror", if it's defined. url = self.host.appRunner.superMirrorUrl + urlbase tryUrls.append((url, False)) if self.host.mirrors: # Choose two mirrors at random. mirrors = self.host.mirrors[:] for i in range(2): mirror = random.choice(mirrors) mirrors.remove(mirror) url = mirror + urlbase tryUrls.append((url, False)) if not mirrors: break # After trying two mirrors and failing (or if there are no # mirrors), go get it from the original host. url = self.host.downloadUrlPrefix + urlbase tryUrls.append((url, False)) # And finally, if the original host also fails, try again with # a cache-buster. tryUrls.append((url, True)) for url, cacheBust in tryUrls: request = DocumentSpec(url) if cacheBust: # On the last attempt to download a particular file, # we bust through the cache: append a query string to # do this. url += '?' + str(int(time.time())) request = DocumentSpec(url) request.setCacheControl(DocumentSpec.CCNoCache) self.notify.info("%s downloading %s" % (self.packageName, url)) if not filename: filename = fileSpec.filename targetPathname = Filename(self.getPackageDir(), filename) targetPathname.setBinary() channel = self.http.makeChannel(False) # If there's a previous partial download, attempt to resume it. bytesStarted = 0 if allowPartial and not cacheBust and targetPathname.exists(): bytesStarted = targetPathname.getFileSize() if bytesStarted < 1024*1024: # Not enough bytes downloaded to be worth the risk of # a partial download. bytesStarted = 0 elif bytesStarted >= fileSpec.size: # Couldn't possibly be our file. bytesStarted = 0 if bytesStarted: self.notify.info("Resuming %s after %s bytes already downloaded" % (url, bytesStarted)) # Make sure the file is writable. os.chmod(targetPathname.toOsSpecific(), 0o644) channel.beginGetSubdocument(request, bytesStarted, 0) else: # No partial download possible; get the whole file. targetPathname.makeDir() targetPathname.unlink() channel.beginGetDocument(request) channel.downloadToFile(targetPathname) while channel.run(): if step: step.bytesDone = channel.getBytesDownloaded() + channel.getFirstByteDelivered() if step.bytesDone > step.bytesNeeded: # Oops, too much data. Might as well abort; # it's the wrong file. self.notify.warning("Got more data than expected for download %s" % (url)) break self.__updateStepProgress(step) if taskMgr.destroyed: # If the task manager has been destroyed, we must # be shutting down. Get out of here. self.notify.warning("Task Manager destroyed, aborting %s" % (url)) yield self.stepFailed; return yield self.stepContinue if step: step.bytesDone = channel.getBytesDownloaded() + channel.getFirstByteDelivered() self.__updateStepProgress(step) if not channel.isValid(): self.notify.warning("Failed to download %s" % (url)) elif not fileSpec.fullVerify(self.getPackageDir(), pathname = targetPathname, notify = self.notify): self.notify.warning("After downloading, %s incorrect" % (Filename(fileSpec.filename).getBasename())) # This attempt failed. Maybe the original contents.xml # file is stale. Try re-downloading it now, just to be # sure. if self.host.redownloadContentsFile(self.http): # Yes! Go back and start over from the beginning. yield self.restartDownload; return else: # Success! yield self.stepComplete; return # Maybe the mirror is bad. Go back and try the next # mirror. # All attempts failed. Maybe the original contents.xml file # is stale. Try re-downloading it now, just to be sure. if self.host.redownloadContentsFile(self.http): # Yes! Go back and start over from the beginning. yield self.restartDownload; return # All mirrors failed; the server (or the internet connection) # must be just fubar. yield self.stepFailed; return
def __unpackArchive(self, step): """ Unpacks any files in the archive that want to be unpacked to disk. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ if not self.extracts: # Nothing to extract. self.hasPackage = True yield self.stepComplete; return if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # We're not allowed to! yield self.stepFailed; return self.updated = True mfPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) self.notify.info("Unpacking %s" % (mfPathname)) mf = Multifile() if not mf.openRead(mfPathname): self.notify.warning("Couldn't open %s" % (mfPathname)) yield self.stepFailed; return allExtractsOk = True step.bytesDone = 0 for file in self.extracts: i = mf.findSubfile(file.filename) if i == -1: self.notify.warning("Not in Multifile: %s" % (file.filename)) allExtractsOk = False continue targetPathname = Filename(self.getPackageDir(), file.filename) targetPathname.setBinary() targetPathname.unlink() if not mf.extractSubfile(i, targetPathname): self.notify.warning("Couldn't extract: %s" % (file.filename)) allExtractsOk = False continue if not file.quickVerify(self.getPackageDir(), notify = self.notify): self.notify.warning("After extracting, still incorrect: %s" % (file.filename)) allExtractsOk = False continue # Make sure it's executable, and not writable. os.chmod(targetPathname.toOsSpecific(), 0o555) step.bytesDone += file.size self.__updateStepProgress(step) if taskMgr.destroyed: # If the task manager has been destroyed, we must # be shutting down. Get out of here. self.notify.warning("Task Manager destroyed, aborting unpacking %s" % (mfPathname)) yield self.stepFailed; return yield self.stepContinue if not allExtractsOk: yield self.stepFailed; return self.hasPackage = True yield self.stepComplete; return
class DirectNewsFrame(DirectObject.DirectObject): TaskName = 'HtmlViewUpdateTask' TaskChainName = 'RedownladTaskChain' RedownloadTaskName = 'RedownloadNewsTask' NewsBaseDir = config.GetString('news-base-dir', '/httpNews') NewsStageDir = config.GetString('news-stage-dir', 'news') FrameDimensions = (-1.30666637421, 1.30666637421, -0.751666665077, 0.751666665077) notify = DirectNotifyGlobal.directNotify.newCategory('DirectNewsFrame') NewsIndexFilename = config.GetString('news-index-filename', 'http_news_index.txt') NewsOverHttp = config.GetBool('news-over-http', True) CacheIndexFilename = 'cache_index.txt' SectionIdents = ['hom', 'new', 'evt', 'tot', 'att', 'tnr'] def __init__(self, parent=aspect2d): DirectObject.DirectObject.__init__(self) self.accept('newsSnapshot', self.doSnapshot) self.active = False self.parent = parent self.issues = [] self.accept('newsChangeWeek', self.changeWeek) self.curIssueIndex = 0 self.strFilenames = None self.redownloadingNews = False self.startRedownload = datetime.datetime.now() self.endRedownload = datetime.datetime.now() self.load() self.percentDownloaded = 0.0 self.numIssuesExpected = 0 self.needsParseNews = True self.newsIndexEntries = [] if self.NewsOverHttp: self.redownloadNews() self.accept('newIssueOut', self.handleNewIssueOut) self.accept('clientCleanup', self.handleClientCleanup) return def parseNewsContent(self): if not self.needsParseNews: return self.needsParseNews = False result = False newsDir = self.findNewsDir() if newsDir: allHomeFiles = self.getAllHomeFilenames(newsDir) self.notify.debug('len allHomeFiles = %s' % len(allHomeFiles)) self.numIssuesExpected = len(allHomeFiles) if allHomeFiles: for myIssueIndex, oneHomeFile in enumerate(allHomeFiles): if type(oneHomeFile) == type(''): justFilename = oneHomeFile else: justFilename = oneHomeFile.getFilename().getBasename() self.notify.debug('parseNewContent %s' % justFilename) parts = justFilename.split('_') dateStr = parts[3] majorVer, minorVer = self.calcIssueVersion(dateStr) if majorVer == 1: oneIssue = IssueFrame.IssueFrame( self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames) elif majorVer == 2: oneIssue = IssueFrameV2.IssueFrameV2( self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames, self.newsIndexEntries) else: self.notify.warning( 'Dont know how to handle version %s, asuming v2' % majorVer) oneIssue = IssueFrameV2.IssueFrameV2( self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames, self.newsIndexEntries) oneIssue.hide() self.issues.append(oneIssue) if self.issues: self.issues[(-1)].show() self.curIssueIndex = len(self.issues) - 1 result = True if hasattr(base.cr, 'inGameNewsMgr') and base.cr.inGameNewsMgr: self.createdTime = base.cr.inGameNewsMgr.getLatestIssue() self.notify.debug('setting created time to latest issue %s' % self.createdTime) else: self.createdTime = base.cr.toontownTimeManager.getCurServerDateTime( ) self.notify.debug('setting created time cur server time %s' % self.createdTime) return result def getAllHomeFilenames(self, newsDir): self.notify.debug('getAllHomeFilenames') newsDirAsFile = vfs.getFile(Filename(newsDir)) fileList = newsDirAsFile.scanDirectory() fileNames = fileList.getFiles() self.notify.debug('filenames=%s' % str(fileNames)) homeFileNames = set([]) for name in fileNames: self.notify.debug('processing %s' % name) baseName = name.getFilename().getBasename() self.notify.debug('baseName=%s' % baseName) if 'hom1.' in baseName: homeFileNames.add(name) else: self.notify.debug('hom1. not in baseName') if not homeFileNames: self.notify.warning('couldnt find hom1. in %s' % fileNames) self.setErrorMessage(TTLocalizer.NewsPageNoIssues) return [] def fileCmp(fileA, fileB): return fileA.getFilename().compareTo(fileB.getFilename()) homeFileNames = list(homeFileNames) homeFileNames.sort(cmp=fileCmp) self.notify.debug('returned homeFileNames=%s' % homeFileNames) return homeFileNames def findNewsDir(self): if self.NewsOverHttp: return self.NewsStageDir else: searchPath = DSearchPath() if AppRunnerGlobal.appRunner: searchPath.appendDirectory( Filename.expandFrom('$TT_3_5_ROOT/phase_3.5/models/news')) else: basePath = os.path.expandvars('$TTMODELS') or './ttmodels' searchPath.appendDirectory( Filename.fromOsSpecific(basePath + '/built/' + self.NewsBaseDir)) searchPath.appendDirectory(Filename(self.NewsBaseDir)) pfile = Filename(self.NewsIndexFilename) found = vfs.resolveFilename(pfile, searchPath) if not found: self.notify.warning('findNewsDir - no path: %s' % self.NewsIndexFilename) self.setErrorMessage(TTLocalizer.NewsPageErrorDownloadingFile % self.NewsIndexFilename) return None self.notify.debug('found index file %s' % pfile) realDir = pfile.getDirname() return realDir def load(self): self.loadBackground() def loadBackground(self): upsellBackground = loader.loadModel( 'phase_3.5/models/gui/tt_m_gui_ign_newsStatusBackground') imageScaleX = self.FrameDimensions[1] - self.FrameDimensions[0] imageScaleY = self.FrameDimensions[3] - self.FrameDimensions[2] self.backFrame = DirectFrame(parent=self.parent, image=upsellBackground, image_scale=(imageScaleX, 1, imageScaleY), frameColor=(1, 1, 1, 0), frameSize=self.FrameDimensions, pos=(0, 0, 0), relief=DGG.FLAT, text=TTLocalizer.NewsPageDownloadingNews1, text_scale=0.06, text_pos=(0, -0.4)) def addDownloadingTextTask(self): self.removeDownloadingTextTask() task = taskMgr.doMethodLater(1, self.loadingTextTask, 'DirectNewsFrameDownloadingTextTask') task.startTime = globalClock.getFrameTime() self.loadingTextTask(task) def removeDownloadingTextTask(self): taskMgr.remove('DirectNewsFrameDownloadingTextTask') def loadMainPage(self): self.mainFrame = DirectFrame(parent=self.backFrame, frameSize=self.FrameDimensions, frameColor=(1, 0, 0, 1)) def activate(self): if hasattr( self, 'createdTime' ) and self.createdTime < base.cr.inGameNewsMgr.getLatestIssue( ) and self.NewsOverHttp and not self.redownloadingNews: self.redownloadNews() else: self.addDownloadingTextTask() if self.needsParseNews and not self.redownloadingNews: self.parseNewsContent() self.active = True def deactivate(self): self.removeDownloadingTextTask() self.active = False def unload(self): self.removeDownloadingTextTask() result = taskMgr.remove(self.RedownloadTaskName) self.ignore('newsSnapshot') self.ignore('newsChangeWeek') self.ignore('newIssueOut') self.ignore('clientCleanup') def handleClientCleanup(self): pass def doSnapshot(self): pass def changeWeek(self, issueIndex): if 0 <= issueIndex and issueIndex < len(self.issues): self.issues[self.curIssueIndex].hide() self.issues[issueIndex].show() self.curIssueIndex = issueIndex def loadingTextTask(self, task): timeIndex = int(globalClock.getFrameTime() - task.startTime) % 3 timeStrs = (TTLocalizer.NewsPageDownloadingNews0, TTLocalizer.NewsPageDownloadingNews1, TTLocalizer.NewsPageDownloadingNews2) textToDisplay = timeStrs[timeIndex] % int(self.percentDownloaded * 100) if self.backFrame['text'] != textToDisplay: if TTLocalizer.NewsPageDownloadingNewsSubstr in self.backFrame[ 'text']: self.backFrame['text'] = textToDisplay return task.again def setErrorMessage(self, errText): self.backFrame['text'] = errText def redownloadNews(self): if self.redownloadingNews: self.notify.warning( 'averting potential crash redownloadNews called twice, just returning' ) return else: self.percentDownloaded = 0.0 self.notify.info('starting redownloadNews') self.startRedownload = datetime.datetime.now() self.redownloadingNews = True self.addDownloadingTextTask() for issue in self.issues: issue.destroy() self.issues = [] self.curIssueIndex = 0 self.strFilenames = None self.needsParseNews = True self.newsUrl = self.getInGameNewsUrl() self.newsDir = Filename(self.findNewsDir()) Filename(self.newsDir + '/.').makeDir() http = HTTPClient.getGlobalPtr() self.url = self.newsUrl + self.NewsIndexFilename self.ch = http.makeChannel(True) self.ch.beginGetDocument(self.url) self.rf = Ramfile() self.ch.downloadToRam(self.rf) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadIndexTask, self.RedownloadTaskName) return def downloadIndexTask(self, task): if self.ch.run(): return task.cont if not self.ch.isValid(): self.notify.warning('Unable to download %s' % self.url) self.redownloadingNews = False return task.done self.newsFiles = [] filename = self.rf.readline() while filename: filename = filename.strip() if filename: self.newsFiles.append(filename) filename = self.rf.readline() del self.rf self.newsFiles.sort() self.newsIndexEntries = list(self.newsFiles) self.notify.info('Server lists %s news files' % len(self.newsFiles)) self.notify.debug('self.newsIndexEntries=%s' % self.newsIndexEntries) self.readNewsCache() for basename in os.listdir(self.newsDir.toOsSpecific()): if basename != self.CacheIndexFilename and basename not in self.newsCache: junk = Filename(self.newsDir, basename) self.notify.info('Removing %s' % junk) junk.unlink() self.nextNewsFile = 0 return self.downloadNextFile(task) def downloadNextFile(self, task): while self.nextNewsFile < len( self.newsFiles) and 'aaver' in self.newsFiles[ self.nextNewsFile]: self.nextNewsFile += 1 if self.nextNewsFile >= len(self.newsFiles): self.notify.info('Done downloading news.') self.percentDownloaded = 1 del self.newsFiles del self.nextNewsFile del self.newsUrl del self.newsDir del self.ch del self.url if hasattr(self, 'filename'): del self.filename self.redownloadingNews = False if self.active: self.parseNewsContent() return task.done self.percentDownloaded = float(self.nextNewsFile) / float( len(self.newsFiles)) self.filename = self.newsFiles[self.nextNewsFile] self.nextNewsFile += 1 self.url = self.newsUrl + self.filename localFilename = Filename(self.newsDir, self.filename) self.notify.info('testing for %s' % localFilename.getFullpath()) doc = DocumentSpec(self.url) if self.filename in self.newsCache: size, date = self.newsCache[self.filename] if date and localFilename.exists() and ( size == 0 or localFilename.getFileSize() == size): doc.setDate(date) doc.setRequestMode(doc.RMNewer) self.ch.beginGetDocument(doc) self.ch.downloadToFile(localFilename) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadCurrentFileTask, self.RedownloadTaskName) def downloadCurrentFileTask(self, task): if self.ch.run(): return task.cont if self.ch.getStatusCode() == 304: self.notify.info('already cached: %s' % self.filename) return self.downloadNextFile(task) localFilename = Filename(self.newsDir, self.filename) if not self.ch.isValid(): self.notify.warning('Unable to download %s' % self.url) localFilename.unlink() if self.filename in self.newsCache: del self.newsCache[self.filename] self.saveNewsCache() return self.downloadNextFile(task) self.notify.info('downloaded %s' % self.filename) size = self.ch.getFileSize() doc = self.ch.getDocumentSpec() date = '' if doc.hasDate(): date = doc.getDate().getString() self.newsCache[self.filename] = (size, date) self.saveNewsCache() return self.downloadNextFile(task) def readNewsCache(self): cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename) self.newsCache = {} if cacheIndexFilename.isRegularFile(): file = open(cacheIndexFilename.toOsSpecific(), 'r') for line in file.readlines(): line = line.strip() keywords = line.split('\t') if len(keywords) == 3: filename, size, date = keywords if filename in self.newsFiles: try: size = int(size) except ValueError: size = 0 self.newsCache[filename] = (size, date) def saveNewsCache(self): cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename) try: file = open(cacheIndexFilename.toOsSpecific(), 'w') except IOError as e: self.notify.warning('error opening news cache file %s: %s' % (cacheIndexFilename, str(e))) return for filename, (size, date) in self.newsCache.items(): print >> file, '%s\t%s\t%s' % (filename, size, date) def handleNewIssueOut(self): if hasattr( self, 'createdTime' ) and base.cr.inGameNewsMgr.getLatestIssue() < self.createdTime: self.createdTime = base.cr.inGameNewsMgr.getLatestIssue() elif self.NewsOverHttp and not self.redownloadingNews: if not self.active: self.redownloadNews() def getInGameNewsUrl(self): result = base.config.GetString( 'fallback-news-url', 'http://cdn.toontown.disney.go.com/toontown/en/gamenews/') override = base.config.GetString('in-game-news-url', '') if override: self.notify.info( 'got an override url, using %s for in game news' % override) result = override else: try: launcherUrl = base.launcher.getValue('GAME_IN_GAME_NEWS_URL', '') if launcherUrl: result = launcherUrl self.notify.info( 'got GAME_IN_GAME_NEWS_URL from launcher using %s' % result) else: self.notify.info( 'blank GAME_IN_GAME_NEWS_URL from launcher, using %s' % result) except: self.notify.warning( 'got exception getting GAME_IN_GAME_NEWS_URL from launcher, using %s' % result) return result def calcIssueVersion(self, dateStr): majorVer = 1 minorVer = 0 for entry in self.newsIndexEntries: if 'aaver' in entry and dateStr in entry: parts = entry.split('_') if len(parts) > 5: try: majorVer = int(parts[5]) except: self.notify.warning('could not int %s' % parts[5]) else: self.notify.warning('expected more than 5 parts in %s' % entry) if len(parts) > 6: try: minorVer = int(parts[6]) except: self.notify.warning('could not int %s' % parts[6]) else: self.notify.warning('expected more than 6 parts in %s' % entry) break return (majorVer, minorVer)
def findDataFilename(name, extract=False, executable=False): """ Resolve a filename along Panda's model-path. :param name: :return: filename or None """ from panda3d.core import Filename, getModelPath from panda3d.core import VirtualFileSystem logging.debug("findDataFilename: "+ name +" on: \n" + str(getModelPath().getValue())) vfs = VirtualFileSystem.getGlobalPtr() fileName = Filename(name) vfile = vfs.findFile(fileName, getModelPath().getValue()) if not vfile: if extract and name.endswith(".exe"): fileName = Filename(name[:-4]) vfile = vfs.findFile(fileName, getModelPath().getValue()) if not vfile: return None fileName = vfile.getFilename() if extract: # see if the file is embedded in some virtual place OR has the wrong perms from panda3d.core import SubfileInfo info = SubfileInfo() needsCopy = not vfile.getSystemInfo(info) or info.getFilename() != fileName if not needsCopy: if executable: # see if on Linux or OSX and not executable try: stat = os.stat(fileName.toOsSpecific()) if (stat.st_mode & 0111) == 0: logging.error("Found %s locally, but not marked executable!", fileName) needsCopy = True except: needsCopy = True if needsCopy: # virtual file needs to be copied out global _tempDir if not _tempDir: import tempfile _tempDir = os.path.realpath(tempfile.mkdtemp()) #print "Temp dir:",_tempDir xpath = _tempDir + '/' + fileName.getBasename() xTarg = Filename.fromOsSpecific(xpath) # on Windows, case-sensitivity must be honored for the following to work xTarg.makeCanonical() print "extracting",fileName,"to",xTarg if not xTarg.exists(): if not vfs.copyFile(fileName, xTarg): raise IOError("extraction failed when copying " + str(fileName) + " to " + str(xTarg)) fileName = xTarg os.chmod(fileName.toOsSpecific(), 0777) return fileName
class World(DirectObject): def __init__(self): base.disableMouse() self.accept("escape", sys.exit) self.accept("enter", self.loadGame) self.accept("C1_START_DOWN", self.loadGame) self.music = base.loader.loadMusic("Sounds/GameMusic2.wav") self.music.setLoop(True) self.music.setVolume(.33 ) self.music.play() self.tractorbeamsound = base.loader.loadSfx("Sounds/tractorbeam.wav") Lvl = 1 self.Lvl = Lvl gamepads = pyPad360() ##print gamepads.setupGamepads() if gamepads.setupGamepads() > 0: gamepads.setupGamepads() taskMgr.add(gamepads.gamepadPollingTask, "gamepadPollingTask") self.gameControls360() self.title = loader.loadModel("Art/skybox.egg") self.title.reparentTo(render) self.title.setScale(1) self.title.setPos(0, 0, -55) self.titleScreen = OnscreenImage(image = 'Art/images/title_screen.png') #self.text1 = OnscreenText(text="Press Enter to Start",style=1, fg=(0.8,0,0.1,1),pos=(0, 0.77), scale = .2,mayChange = 1,align=TextNode.ACenter) self.inGame = False #print self.text1 def loadGame(self): if not self.inGame: self.inGame = True self.title.removeNode() del self.title self.titleScreen.destroy() #self.text1.destroy() #del self.text1 self.startGame() def startGame(self): #if self.inGame == True: self.saucer = Saucer() camera.setPosHpr(0, -40, 73, 0, 0, 0) camera.lookAt(self.saucer.ship) camera.setP(camera.getP() -8) self.loadModels() self.loadHUD() self.setupLights() self.keyMap = {"left":0, "right":0,"w":0,"a":0,"s":0,"d":0,"k":0,"l":0} self.prevtime = 0 self.accept("arrow_right", self.setKey, ["right", 1]) self.accept("arrow_left", self.setKey, ["left", 1]) self.accept("arrow_right-up", self.setKey, ["right", 0]) self.accept("arrow_left-up", self.setKey, ["left", 0]) self.accept("w", self.setKey, ["w", 1]) self.accept("w-up", self.setKey, ["w", 0]) self.accept("s", self.setKey, ["s", 1]) self.accept("s-up", self.setKey, ["s", 0]) self.accept("a", self.setKey, ["a", 1]) self.accept("a-up", self.setKey, ["a", 0]) self.accept("d", self.setKey, ["d", 1]) self.accept("d-up", self.setKey, ["d", 0]) self.accept("k", self.setKey, ["k", 1]) self.accept("k-up", self.setKey, ["k", 0]) self.accept("l", self.setKey, ["l", 1]) self.accept("l-up", self.setKey, ["l", 0]) self.accept("enter", self.blank) self.accept("C1_START_DOWN", self.blank) self.mydir = os.path.abspath(sys.path[0]) self.mydir = Filename.fromOsSpecific(self.mydir).getFullpath() self.mydir = Filename(self.mydir) self.mydir = self.mydir.toOsSpecific() self.setupWASD() taskMgr.add(self.rotateWorld, "rotateWorldTask") taskMgr.add(self.missileSeek, "missileSeekTask") self.animalsleft = 0 self.missiles = [] taskMgr.add(self.textTask, "textTask") self.saucer.ship.setColorScale(1,1,1,1) self.missileSound = base.loader.loadSfx("Sounds/tankshot.wav") self.missileHitSound = base.loader.loadSfx("Sounds/missile.wav") self.xspeed = 0 self.yspeed = 0 #For recycler self.xbounds = 130 self.currentpickupable = 0 self.loadLevel() base.cTrav = CollisionTraverser() #set the collision handler to send event messages on collision self.cHandler = CollisionHandlerEvent() # %in is substituted with the name of the into object self.cHandler.setInPattern("%fn-%in") self.setupCollisions() self.accept("beam-pickupable", self.beamCollide) self.accept("ship-tankdetect", self.tankShoot) self.accept("missile-ship", self.missileHit) #print "Level " + str(self.Lvl) self.accept("space", self.loseGame)#Goes to Level Failed screen. For testing purposes self.accept("C1_X_DOWN", self.loseGame) self.accept("backspace", self.winGame) #Goes to Level Complete screen. For testing purposes self.accept("C1_Y_DOWN", self.winGame) def loseGame(self): self.levelComplete = False #Clear stuff taskMgr.remove('rotateWorldTask') taskMgr.remove('textTask') taskMgr.remove('abductTask') taskMgr.remove('moveTask') taskMgr.remove('missileSeekTask') taskMgr.remove('ParticleTaskTask') self.env.removeNode() del self.env self.saucer.ship.removeNode() del self.saucer.ship self.saucer.beam.removeNode() del self.saucer.beam #self.timeroutline.removeNode() #del self.timeroutline self.TimeText.destroy() del self.TimeText for i in range(0,len(self.pickupables)): self.pickupables[i].pickup.removeNode() del self.pickupables[i].pickup self.texte = OnscreenText(text="You Lose!",style=1, fg=(0.8,0,0.1,1),pos=(0, 0), scale = .2,mayChange = 1,align=TextNode.ACenter) self.textd = OnscreenText(text="Press Enter or Start to restart!",style=1, fg=(0.8,0,0.1,1),pos=(0, -.88), scale = .06,mayChange = 1,align=TextNode.ACenter) self.accept("enter", self.nextLevel) self.accept("C1_START_DOWN", self.nextLevel) def winGame(self): self.levelComplete = True #Clear Stuff taskMgr.remove('rotateWorldTask') taskMgr.remove('textTask') taskMgr.remove('abductTask') taskMgr.remove('moveTask') taskMgr.remove('missileSeekTask') self.env.removeNode() del self.env self.saucer.ship.removeNode() del self.saucer.ship self.saucer.beam.removeNode() del self.saucer.beam self.AnimalsLeft.destroy() del self.AnimalsLeft self.AnimalsLeftText.destroy() del self.AnimalsLeftText for i in range(0,len(self.pickupables)): self.pickupables[i].pickup.removeNode() del self.pickupables[i].pickup #if self.medal == "Gold": # self.medalImage = OnscreenImage(image = 'Art/gold.png', pos = (1.1, 0, .46), scale = (.2,1,.2)) #elif self.medal == "Silver": # self.medalImage = OnscreenImage(image = 'Art/silver.png', pos = (1.1, 0, .46), scale = (.125,1,.225)) #elif self.medal == "Bronze": # self.medalImage = OnscreenImage(image = 'Art/bronze.png', pos = (1.1, 0, .46), scale = (.15,.1,.2)) if self.Lvl < 4: self.texte = OnscreenText(text="Level Complete!",style=1, fg=(0.8,0,0.1,1),pos=(0, 0), scale = .2,mayChange = 1,align=TextNode.ACenter) self.textd = OnscreenText(text="Press Enter or Start to go to next level!",style=1, fg=(0.8,0,0.1,1),pos=(0, -.88), scale = .06,mayChange = 1,align=TextNode.ACenter) self.Lvl += 1 self.accept("enter", self.nextLevel) self.accept("C1_START_DOWN", self.nextLevel) else: self.creditsScreen = OnscreenImage(image = 'Art/images/credits_screen.png') #self.texte = OnscreenText(text="You Finished the Game!",style=1, fg=(0.8,0,0.1,1),pos=(0, 0), scale = .2,mayChange = 1,align=TextNode.ACenter) def nextLevel(self): self.skybox.removeNode() del self.skybox self.texte.destroy() del self.texte self.textd.destroy() del self.textd if self.levelComplete == True: #self.timeroutline.removeNode() #del self.timeroutline self.TimeText.destroy() del self.TimeText #self.medalImage.removeNode() #del self.medalImage if self.levelComplete == False: self.AnimalsLeft.destroy() del self.AnimalsLeft self.AnimalsLeftText.destroy() del self.AnimalsLeftText for p in self.pickupables: p.particle.disable() self.saucer.abductp.disable() self.startGame() def gameControls360(self): #Accept each message and do something based on the button self.accept("C1_A_DOWN", self.setKey, ["k", 1]) self.accept("C1_A_UP", self.setKey,["k",0]) self.accept("C1_B_DOWN", self.setKey, ["l", 1]) self.accept("C1_B_UP", self.setKey,["l",0]) self.accept("C1_DPAD_UP", self.setKey, ["w", 1]) self.accept("C1_DPAD_DOWN", self.setKey,["s",1]) self.accept("C1_DPAD_LEFT", self.setKey, ["a", 1]) self.accept("C1_DPAD_RIGHT", self.setKey, ["d", 1]) self.accept("C1_DPAD_NONE", self.stop,["w",0,"s",0,"a",0,"d",0]) self.accept("C1_DPAD_UPLEFT", self.diagkeys, ["w",1,"a",1]) self.accept("C1_DPAD_UPRIGHT", self.diagkeys, ["w",1,"d",1]) self.accept("C1_DPAD_DOWNLEFT", self.diagkeys, ["s",1,"a",1]) self.accept("C1_DPAD_DOWNRIGHT", self.diagkeys, ["s",1,"d",1]) self.accept("C1_LSTICK_HARDUP", self.setKey, ["w", 1]) self.accept("C1_LSTICK_SLIGHTUP", self.setKey, ["w", 0]) self.accept("C1_LSTICK_HARDDOWN", self.setKey,["s",1]) self.accept("C1_LSTICK_SLIGHTDOWN", self.setKey,["s",0]) self.accept("C1_LSTICK_HARDLEFT", self.setKey, ["a", 1]) self.accept("C1_LSTICK_SLIGHTLEFT", self.setKey, ["a", 0]) self.accept("C1_LSTICK_HARDRIGHT", self.setKey, ["d", 1]) self.accept("C1_LSTICK_SLIGHTRIGHT", self.setKey, ["d", 0]) def blank(self): x=1 def stop(self, key1, value1, key2, value2, key3, value3, key4, value4): self.keyMap[key1] = value1 self.keyMap[key2] = value2 self.keyMap[key3] = value3 self.keyMap[key4] = value4 def diagkeys(self, key1, value1, key2, value2): self.keyMap[key1] = value1 self.keyMap[key2] = value2 def setupWASD(self): self.accept("w", self.setKey, ["w", 1]) self.accept("w-up", self.setKey, ["w", 0]) self.accept("s", self.setKey, ["s", 1]) self.accept("s-up", self.setKey, ["s", 0]) self.accept("a", self.setKey, ["a", 1]) self.accept("a-up", self.setKey, ["a", 0]) self.accept("d", self.setKey, ["d", 1]) self.accept("d-up", self.setKey, ["d", 0]) def loadLevel(self): #self.map = open("C:\Users\Vanded3\Documents\ufo-game2\Code\Levels\level1.txt") #self.map = "CC0CCCCCCCC000CCCCCCCCCC00CCCCCCCCCCCCC" self.map = open (self.mydir + "\Levels\level" + str(self.Lvl) + ".txt") self.map = [line.rstrip() for line in self.map] self.tex = loader.loadTexture("\Art\images\world" + str(self.Lvl) + "_texture.png") self.env.setTexture(self.tex) #self.terrainlist = [] tsize = 4 self.pickupables = [] #self.animals = [] #self.inanimates = [] #self.hostiles = [] worldhalfwidth = 240 worldradius = 43 for i, row in enumerate(self.map): for j, column in enumerate(row): if column == "-": pass if column == "C": temp = Pickupable("animal","cow") temp.pickup.reparentTo(self.env) #print("in cow") temp.pickup.setScale(1) angle = i * .1 y = worldradius * math.cos(angle) z = worldradius * math.sin(angle) temp.pickup.setPos((j * tsize)-worldhalfwidth, y, z) rotangle = math.degrees(math.atan2((z - 0), (y - 0))) temp.pickup.setHpr(0,rotangle - 90,0) temp.pickup.setH(temp.pickup, random.randint(0,360)) #positioning : i*tsize #temp.pickup.reparentTo(self.env) self.pickupables.append(temp) #print (len(self.pickupables)) if column == "S": temp = Pickupable("animal", "sheep") temp.pickup.setScale(1) angle = i * .1 y = worldradius * math.cos(angle) z= worldradius * math.sin(angle) temp.pickup.setPos((j * tsize)-worldhalfwidth, y, z) rotangle = math.degrees(math.atan2((z - 0), (y - 0))) temp.pickup.setHpr(0,rotangle - 90,0) temp.pickup.setH(temp.pickup, random.randint(0,360)) #positioning : i*tsize temp.pickup.reparentTo(self.env) self.pickupables.append(temp) #print("in S") if column == "P": temp = Pickupable("inanimate", "silo") temp.pickup.setScale(1) angle = i * .1 y = worldradius * math.cos(angle) z= worldradius * math.sin(angle) temp.pickup.setPos((j * tsize)-worldhalfwidth, y, z) rotangle = math.degrees(math.atan2((z - 0), (y - 0))) temp.pickup.setHpr(0,rotangle - 90,0) temp.pickup.setH(temp.pickup, random.randint(0,360)) #positioning : i*tsize temp.pickup.reparentTo(self.env) self.pickupables.append(temp) #print("in P") if column == "0": temp = Pickupable("animal", "pig") temp.pickup.setScale(1) angle = i * .1 y = worldradius * math.cos(angle) z= worldradius * math.sin(angle) temp.pickup.setPos((j * tsize)-worldhalfwidth, y, z) rotangle = math.degrees(math.atan2((z - 0), (y - 0))) temp.pickup.setHpr(0,rotangle - 90,0) temp.pickup.setH(temp.pickup, random.randint(0,360)) #positioning : i*tsize temp.pickup.reparentTo(self.env) self.pickupables.append(temp) #print("in B") if column == "M": temp = Pickupable("hostile", "tank") temp.pickup.setScale(1) angle = i * .1 y = worldradius * math.cos(angle) z= worldradius * math.sin(angle) temp.pickup.setPos((j * tsize)-worldhalfwidth, y, z) rotangle = math.degrees(math.atan2((z - 0), (y - 0))) temp.pickup.setHpr(0,rotangle - 90,0) temp.pickup.setH(temp.pickup, random.randint(0,360)) #positioning : i*tsize temp.pickup.reparentTo(self.env) self.pickupables.append(temp) #print("in M") if column == "N": temp = Pickupable("inanimate", "tractor") temp.pickup.setScale(1) angle = i * .1 y = worldradius * math.cos(angle) z= worldradius * math.sin(angle) temp.pickup.setPos((j * tsize)-worldhalfwidth, y, z) rotangle = math.degrees(math.atan2((z - 0), (y - 0))) temp.pickup.setHpr(0,rotangle - 90,0) temp.pickup.setH(temp.pickup, random.randint(0,360)) #positioning : i*tsize temp.pickup.reparentTo(self.env) self.pickupables.append(temp) #print("in N") if column == "B": temp = Pickupable("inanimate", "barn") temp.pickup.setScale(1) angle = i * .1 y = worldradius * math.cos(angle) z= worldradius * math.sin(angle) temp.pickup.setPos((j * tsize)-worldhalfwidth, y, z) rotangle = math.degrees(math.atan2((z - 0), (y - 0))) temp.pickup.setHpr(0,rotangle - 90,0) temp.pickup.setH(temp.pickup, random.randint(0,360)) #positioning : i*tsize temp.pickup.reparentTo(self.env) self.pickupables.append(temp) #print("in N") if column == "W": temp = Pickupable("inanimate", "cage") temp.pickup.setScale(1) angle = i * .1 y = worldradius * math.cos(angle) z= worldradius * math.sin(angle) temp.pickup.setPos((j * tsize)-worldhalfwidth, y, z) rotangle = math.degrees(math.atan2((z - 0), (y - 0))) temp.pickup.setHpr(0,rotangle - 90,0) temp.pickup.setH(temp.pickup, random.randint(0,360)) #positioning : i*tsize temp.pickup.reparentTo(self.env) self.pickupables.append(temp) #print("in N") #print len(self.pickupables) #self.env.setX(self.env.getX() - 60) #self.env.setP(self.env.getP() + 60) def setKey(self, key, value): self.keyMap[key] = value def rotateWorld(self,task): #Handles saucer movement, world rotation etc elapsed = task.time - self.prevtime self.prevtime = task.time # Create a handle for pointer device #0 #m = base.win.getPointer( 0 ) # Get the absolute [x,y] screen coordinates of the cursor #x = m.getX( ) #y = m.getY( ) centerx = 400 centery = 300 xmov = 0 ymov = 0 accel = 0 dir = -1 if self.keyMap["l"]: self.saucer.drop(self.env) #for object in self.saucer.abductlist: #object.abduct = False #object.pickup.wrtReparentTo(self.env) #object.pickup.setPos(self.saucer.dummy2.getX(),self.saucer.dummy2.getY(),self.saucer.dummy2.getZ()) #camera.lookAt(object.pickup) if self.keyMap["k"]: if self.tractorbeamsound.status() != AudioSound.PLAYING: self.tractorbeamsound.play() self.saucer.beamon = True if self.xspeed > 30: self.xspeed = 30 elif self.xspeed < -30: self.xspeed = -30 if self.yspeed > 30: self.yspeed = 30 elif self.yspeed < -30: self.yspeed = -30 if self.keyMap["w"]: dir = 270 if self.keyMap["s"]: dir = 90 if self.keyMap["a"]: dir = 180 if self.keyMap["d"]: dir = 0 if self.keyMap["w"] and self.keyMap["d"]: dir = 315 if self.keyMap["w"] and self.keyMap["a"]: dir = 225 if self.keyMap["s"] and self.keyMap["a"]: dir = 135 if self.keyMap["s"] and self.keyMap["d"]: dir = 45 if dir != -1: xmov = 26 * math.cos(math.radians(dir)) ymov = 26 * math.sin(math.radians(dir)) if xmov == 0 and ymov == 0: accel = .1 else: accel = .035 else: self.saucer.beamon = False if self.tractorbeamsound.status() == AudioSound.PLAYING: self.tractorbeamsound.stop() if self.keyMap["w"]: dir = 270 if self.keyMap["s"]: dir = 90 if self.keyMap["a"]: dir = 180 if self.keyMap["d"]: dir = 0 if self.keyMap["w"] and self.keyMap["d"]: dir = 315 if self.keyMap["w"] and self.keyMap["a"]: dir = 225 if self.keyMap["s"] and self.keyMap["a"]: dir = 135 if self.keyMap["s"] and self.keyMap["d"]: dir = 45 if dir != -1: xmov = 40 * math.cos(math.radians(dir)) ymov = 40 * math.sin(math.radians(dir)) accel = .07 #if base.win.movePointer( 0, centerx, centery ): # xmov += ( x - centerx ) * 1 # ymov += ( y - centery ) * 1 if self.env.getX() > self.xbounds: if xmov < 0: xmov = 0 elif self.env.getX() < -self.xbounds: if xmov > 0: xmov = 0 self.xspeed = self.xspeed + ( (xmov - self.xspeed) * accel) self.yspeed = self.yspeed + ( (ymov - self.yspeed) * accel) self.env.setX(self.env.getX() + elapsed * -self.xspeed) self.env.setP(self.env.getP() + elapsed * -self.yspeed) self.skybox.setX(self.skybox.getX() + elapsed * -.3 * self.xspeed) self.skybox.setP(self.skybox.getP() + elapsed * -.1 * self.yspeed) self.saucer.ship.setR(self.xspeed * .2) self.saucer.ship.setP(self.yspeed * .2) ##print self.env.getX() return Task.cont def loadModels(self): self.env = loader.loadModel("Art/world1.egg") self.env.reparentTo(render) self.env.setScale(1) self.env.setPos(0, 0, -55) self.skybox = loader.loadModel("Art/skytube.egg") self.skybox.reparentTo(render) self.skybox.setScale(2) self.skybox.setPos(0, 0, 0) self.skybox.setHpr(0,-60,0) #Shadow Code: proj = render.attachNewNode(LensNode('proj')) lens = PerspectiveLens() proj.node().setLens(lens) #The following is for debugging: #proj.node().showFrustum() #proj.find('frustum').setColor(1, 0, 0, 1) proj.reparentTo(render) proj.setPos(self.saucer.ship.getPos()) proj.setZ(-2) proj.setHpr(0,-90,0) tex = loader.loadTexture('Art\UFO_Shadow.png') tex.setWrapU(Texture.WMBorderColor) tex.setWrapV(Texture.WMBorderColor) tex.setBorderColor(VBase4(1, 1, 1, 0)) ts = TextureStage('ts') ts.setSort(1) ts.setMode(TextureStage.MDecal) self.env.projectTexture(ts, tex, proj) def loadHUD(self): #Draw image as outline for timer #self.timeroutline = OnscreenImage(image = 'Art/timer.png', pos = (1.1, 0, .86), scale = (.15,.1,.1)) #self.timeroutline = OnscreenImage(image = 'Art/timer.png', pos = (-.98, 0, .88), scale = (.38,.50,.12)) #Draw num of animals left num = str(200000) self.AnimalsLeft = OnscreenText(text="Animals Collected:",style=1, fg=(1,1,1,1),pos=(-1,.9), scale = .07,mayChange = 1) self.AnimalsLeftText = OnscreenText(text=num,style=1, fg=(1,1,1,1),pos=(-1,0.8), scale = .09,mayChange = 1,align = TextNode.ALeft) #Draw time t = "0:00" self.TimeText = OnscreenText(text=t,style=1, fg=(1,1,1,1),pos=(1,0.85), scale = .09, mayChange = 1, align = TextNode.ALeft) def dCharstr(self,number): theString = str(number) if len(theString) != 2: theString = '0' + theString return theString def textTask(self,task): secondsTime = int(task.time) minutesTime = int(secondsTime/60) self.seconds = secondsTime%60 self.minutes = minutesTime self.mytimer = str(self.minutes) + ":" + self.dCharstr(int(self.seconds)) #self.mytimer = str(self.seconds) self.TimeText.setText(self.mytimer) medal = "No Medal" self.medal = medal if task.time <= 35: self.medal = "Gold" elif task.time > 35 and task.time <=50: self.medal = "Silver" elif task.time > 50: self.medal = "Bronze" self.AnimalsLeftText.setText(str(self.saucer.collected)) if self.saucer.collected > 30: self.winGame() return Task.cont def setupLights(self): """loads initial lighting""" self.dirLight = DirectionalLight("dirLight") self.dirLight.setColor((.6, .6, .6, 1)) #create a NodePath, and attach it directly into the scene self.dirLightNP = render.attachNewNode(self.dirLight) self.dirLightNP.setHpr(0, -25, 0) #the NP that calls setLight is what gets lit render.setLight(self.dirLightNP) # clearLight() turns it off self.ambientLight = AmbientLight("ambientLight") self.ambientLight.setColor((.25, .25, .25, 1)) self.ambientLightNP = render.attachNewNode(self.ambientLight) render.setLight(self.ambientLightNP) def setupCollisions(self): cSphere = CollisionSphere((0,0,0), 2) cNode = CollisionNode("ship") cNode.addSolid(cSphere) cNodePath = self.saucer.ship.attachNewNode(cNode) base.cTrav.addCollider(cNodePath, self.cHandler) #saucer collider cSphere = CollisionSphere((0,0,0), 2) cNode = CollisionNode("beam") cNode.addSolid(cSphere) #set to only be a "from" object cNode.setIntoCollideMask(BitMask32.allOff()) cNodePath = self.saucer.dummy.attachNewNode(cNode) cNodePath.setZ(-36) #cNodePath.show() base.cTrav.addCollider(cNodePath, self.cHandler) #target colliders for p in self.pickupables: cSphere = CollisionSphere((0,0,0), 1) cNode = CollisionNode("pickupable") cNode.addSolid(cSphere) cNodePath = p.pickup.attachNewNode(cNode) if p.type2 == "tank": cSphere = CollisionSphere((0,0,0), 45) cNode = CollisionNode("tankdetect") cNode.addSolid(cSphere) cNodePath = p.pickup.attachNewNode(cNode) #cNodePath.show() def beamCollide(self, cEntry): if self.saucer.beamon: obj = cEntry.getIntoNodePath().getParent() for x in self.pickupables: if (x.pickup == obj): self.saucer.pickUp(x) return def tankShoot(self, cEntry): tank = cEntry.getIntoNodePath() newMissile = Missile() newMissile.model.reparentTo(tank.getParent()) cSphere = CollisionSphere((0,0,0), 2) cNode = CollisionNode("missile") cNode.addSolid(cSphere) cNodePath = newMissile.model.attachNewNode(cNode) base.cTrav.addCollider(cNodePath, self.cHandler) self.missiles.append(newMissile) self.missileSound.play() def missileSeek(self, task): for i in self.missiles: i.seek(self.saucer.ship) return Task.cont def missileHit(self, cEntry): aMissile = cEntry.getFromNodePath().getParent() for i in self.missiles: if i.model == aMissile: self.missileHitSound.play() i.model.removeNode() self.missiles.remove(i) self.saucer.health -= 20 if self.saucer.health <=0: self.loseGame() elif self.saucer.health <= 50: self.saucer.ship.setColorScale(1,.5,.5,1) return
def __unpackArchive(self, step): """ Unpacks any files in the archive that want to be unpacked to disk. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ if not self.extracts: # Nothing to extract. self.hasPackage = True yield self.stepComplete return if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # We're not allowed to! yield self.stepFailed return self.updated = True mfPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) self.notify.info("Unpacking %s" % (mfPathname)) mf = Multifile() if not mf.openRead(mfPathname): self.notify.warning("Couldn't open %s" % (mfPathname)) yield self.stepFailed return allExtractsOk = True step.bytesDone = 0 for file in self.extracts: i = mf.findSubfile(file.filename) if i == -1: self.notify.warning("Not in Multifile: %s" % (file.filename)) allExtractsOk = False continue targetPathname = Filename(self.getPackageDir(), file.filename) targetPathname.setBinary() targetPathname.unlink() if not mf.extractSubfile(i, targetPathname): self.notify.warning("Couldn't extract: %s" % (file.filename)) allExtractsOk = False continue if not file.quickVerify(self.getPackageDir(), notify=self.notify): self.notify.warning("After extracting, still incorrect: %s" % (file.filename)) allExtractsOk = False continue # Make sure it's executable, and not writable. os.chmod(targetPathname.toOsSpecific(), 0o555) step.bytesDone += file.size self.__updateStepProgress(step) if taskMgr.destroyed: # If the task manager has been destroyed, we must # be shutting down. Get out of here. self.notify.warning( "Task Manager destroyed, aborting unpacking %s" % (mfPathname)) yield self.stepFailed return yield self.stepContinue if not allExtractsOk: yield self.stepFailed return self.hasPackage = True yield self.stepComplete return
def processModel(path): scene = loadModel(path) if scene.isEmpty(): print("Error converting `{0}`!".format(path)) return fPath = Filename.fromOsSpecific(path) outputPath = Filename.toOsSpecific( Filename("bam2smd/" + fPath.getDirname() + "/" + fPath.getBasenameWoExtension() + "/")) if not os.path.exists(outputPath): os.makedirs(outputPath) isCharacter = not scene.find("**/+Character").isEmpty() isAnimation = not scene.find("**/+AnimBundleNode").isEmpty() if not isAnimation: if isCharacter: nodes = Skeleton(scene.findAllMatches("**/+Character")) else: nodes = Skeleton(None) names = {} for geomNp in scene.findAllMatches("**/+GeomNode"): smd = "version 1\n" smd += str(nodes) smd += "skeleton\n" smd += "time 0\n" if isCharacter: boneIds = sorted(nodes.bones.keys()) for iBone in range(len(boneIds)): boneId = boneIds[iBone] bone = nodes.bones[boneId] if isinstance(bone, CharacterJoint): boneTform = bone.getTransformState() pos = boneTform.getPos() boneMat = boneTform.getMat().getUpper3() #boneMat.transposeInPlace() rot = mat3NormalizedToEulO(boneMat) else: pos = Vec3() rot = Vec3() smd += boneFrameString(boneId, pos, rot) else: smd += "0 0 0 0 0 0 0\n" smd += "end\n" smd += "triangles\n" for geom in geomNp.node().getGeoms(): geom = geom.decompose() vdata = geom.getVertexData() blendTable = vdata.getTransformBlendTable() for prim in geom.getPrimitives(): numTris = prim.getNumPrimitives() for nTri in range(numTris): start = prim.getPrimitiveStart(nTri) end = prim.getPrimitiveEnd(nTri) smd += "no_material\n" for primVert in range(start, end): vertIdx = prim.getVertex(primVert) reader = GeomVertexReader(vdata) reader.setColumn(InternalName.getVertex()) reader.setRow(vertIdx) pos = reader.getData3f() uv = Vec2(0, 0) if vdata.hasColumn(InternalName.getTexcoord()): reader.setColumn(InternalName.getTexcoord()) reader.setRow(vertIdx) uv = reader.getData2f() norm = Vec3.forward() if vdata.hasColumn(InternalName.getNormal()): reader.setColumn(InternalName.getNormal()) reader.setRow(vertIdx) norm = reader.getData3f() smd += "0 {0:.6f} {1:.6f} {2:.6f} {3:.6f} {4:.6f} {5:.6f} {6:.6f} {7:.6f} ".format( pos[0], pos[1], pos[2], norm[0], norm[1], norm[2], uv[0], uv[1]) if (isCharacter and blendTable and vdata.getNumArrays() > 1 and vdata.getArray(1).hasColumn( InternalName.getTransformBlend())): reader.setColumn( 1, vdata.getArray( 1).getArrayFormat().getColumn( InternalName.getTransformBlend())) reader.setRow(vertIdx) nBlend = reader.getData1i() blend = blendTable.getBlend(nBlend) numTransforms = blend.getNumTransforms() smd += "{0} ".format(numTransforms) for nTransform in range(numTransforms): transform = blend.getTransform(nTransform) if isinstance(transform, JointVertexTransform): boneId = nodes.getBoneId( transform.getJoint()) smd += "{0} {1:.6f} ".format( boneId, blend.getWeight(nTransform)) else: smd += "1 0 1.0" smd += "\n" smd += "end\n" smdFile = geomNp.getName() if len(smdFile) == 0: smdFile = getUnknownName() elif names.get(smdFile, 0) > 0: smdFile = smdFile + "_{0}".format(names[smdFile]) names[smdFile] += 1 else: names[smdFile] = 1 smdFile += ".smd" outFile = open(outputPath + "\\" + smdFile, "w") outFile.write(smd) outFile.flush() outFile.close() else: bundles = scene.findAllMatches("**/+AnimBundleNode") bundle = bundles[0].node().getBundle() nodes = Skeleton(bundles) smd = "version 1\n" smd += str(nodes) smd += "skeleton\n" numFrames = bundle.getNumFrames() boneIds = sorted(nodes.bones.keys()) for iFrame in range(numFrames): smd += "time {0}\n".format(iFrame) for iBone in range(len(boneIds)): bone = nodes.getBone(boneIds[iBone]) if isinstance(bone, AnimChannelACMatrixSwitchType): boneFrameMat = Mat4() bone.getValueNoScaleShear(iFrame, boneFrameMat) boneFrameTransform = TransformState.makeMat(boneFrameMat) pos = boneFrameTransform.getPos() rotMat = boneFrameMat.getUpper3() #rotMat.transposeInPlace() rot = mat3NormalizedToEulO(rotMat) smd += boneFrameString(boneIds[iBone], pos, rot) smd += "end\n" smdFile = fPath.getBasenameWoExtension() + ".smd" outFile = open(outputPath + "\\" + smdFile, "w") outFile.write(smd) outFile.flush() outFile.close()
def __readDescFile(self): """ Reads the desc xml file for this particular package, assuming it's been already downloaded and verified. Returns true on success, false on failure. """ if self.hasDescFile: # No need to read it again. return True if self.solo: # If this is a "solo" package, we don't actually "read" # the desc file; that's the entire contents of the # package. self.hasDescFile = True self.hasPackage = True return True filename = Filename(self.getPackageDir(), self.descFileBasename) if not hasattr(core, 'TiXmlDocument'): return False doc = core.TiXmlDocument(filename.toOsSpecific()) if not doc.LoadFile(): return False xpackage = doc.FirstChildElement('package') if not xpackage: return False try: self.patchVersion = int(xpackage.Attribute('patch_version') or '') except ValueError: self.patchVersion = None try: perPlatform = int(xpackage.Attribute('per_platform') or '') except ValueError: perPlatform = False if perPlatform != self.perPlatform: self.notify.warning("per_platform disagreement on package %s" % (self.packageName)) self.displayName = None xconfig = xpackage.FirstChildElement('config') if xconfig: # The name for display to an English-speaking user. self.displayName = xconfig.Attribute('display_name') # True if any apps that use this package must be GUI apps. guiApp = xconfig.Attribute('gui_app') if guiApp: self.guiApp = int(guiApp) # The uncompressed archive, which will be mounted directly, # and also used for patching. xuncompressedArchive = xpackage.FirstChildElement( 'uncompressed_archive') if xuncompressedArchive: self.uncompressedArchive = FileSpec() self.uncompressedArchive.loadXml(xuncompressedArchive) # The compressed archive, which is what is downloaded. xcompressedArchive = xpackage.FirstChildElement('compressed_archive') if xcompressedArchive: self.compressedArchive = FileSpec() self.compressedArchive.loadXml(xcompressedArchive) # The list of files that should be extracted to disk. self.extracts = [] xextract = xpackage.FirstChildElement('extract') while xextract: file = FileSpec() file.loadXml(xextract) self.extracts.append(file) xextract = xextract.NextSiblingElement('extract') # The list of additional packages that must be installed for # this package to function properly. self.requires = [] xrequires = xpackage.FirstChildElement('requires') while xrequires: packageName = xrequires.Attribute('name') version = xrequires.Attribute('version') hostUrl = xrequires.Attribute('host') if packageName and hostUrl: host = self.host.appRunner.getHostWithAlt(hostUrl) self.requires.append((packageName, version, host)) xrequires = xrequires.NextSiblingElement('requires') self.hasDescFile = True # Now that we've read the desc file, go ahead and use it to # verify the download status. if self.__checkArchiveStatus(): # It's all fully downloaded, unpacked, and ready. self.hasPackage = True return True # Still have to download it. self.__buildInstallPlans() return True
def __downloadFile(self, step, fileSpec, urlbase=None, filename=None, allowPartial=False): """ Downloads the indicated file from the host into packageDir. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # We're not allowed to download anything. yield self.stepFailed return self.updated = True if not urlbase: urlbase = self.descFileDirname + '/' + fileSpec.filename # Build up a list of URL's to try downloading from. Unlike # the C++ implementation in P3DPackage.cxx, here we build the # URL's in forward order. tryUrls = [] if self.host.appRunner and self.host.appRunner.superMirrorUrl: # We start with the "super mirror", if it's defined. url = self.host.appRunner.superMirrorUrl + urlbase tryUrls.append((url, False)) if self.host.mirrors: # Choose two mirrors at random. mirrors = self.host.mirrors[:] for i in range(2): mirror = random.choice(mirrors) mirrors.remove(mirror) url = mirror + urlbase tryUrls.append((url, False)) if not mirrors: break # After trying two mirrors and failing (or if there are no # mirrors), go get it from the original host. url = self.host.downloadUrlPrefix + urlbase tryUrls.append((url, False)) # And finally, if the original host also fails, try again with # a cache-buster. tryUrls.append((url, True)) for url, cacheBust in tryUrls: request = DocumentSpec(url) if cacheBust: # On the last attempt to download a particular file, # we bust through the cache: append a query string to # do this. url += '?' + str(int(time.time())) request = DocumentSpec(url) request.setCacheControl(DocumentSpec.CCNoCache) self.notify.info("%s downloading %s" % (self.packageName, url)) if not filename: filename = fileSpec.filename targetPathname = Filename(self.getPackageDir(), filename) targetPathname.setBinary() channel = self.http.makeChannel(False) # If there's a previous partial download, attempt to resume it. bytesStarted = 0 if allowPartial and not cacheBust and targetPathname.exists(): bytesStarted = targetPathname.getFileSize() if bytesStarted < 1024 * 1024: # Not enough bytes downloaded to be worth the risk of # a partial download. bytesStarted = 0 elif bytesStarted >= fileSpec.size: # Couldn't possibly be our file. bytesStarted = 0 if bytesStarted: self.notify.info( "Resuming %s after %s bytes already downloaded" % (url, bytesStarted)) # Make sure the file is writable. os.chmod(targetPathname.toOsSpecific(), 0o644) channel.beginGetSubdocument(request, bytesStarted, 0) else: # No partial download possible; get the whole file. targetPathname.makeDir() targetPathname.unlink() channel.beginGetDocument(request) channel.downloadToFile(targetPathname) while channel.run(): if step: step.bytesDone = channel.getBytesDownloaded( ) + channel.getFirstByteDelivered() if step.bytesDone > step.bytesNeeded: # Oops, too much data. Might as well abort; # it's the wrong file. self.notify.warning( "Got more data than expected for download %s" % (url)) break self.__updateStepProgress(step) if taskMgr.destroyed: # If the task manager has been destroyed, we must # be shutting down. Get out of here. self.notify.warning("Task Manager destroyed, aborting %s" % (url)) yield self.stepFailed return yield self.stepContinue if step: step.bytesDone = channel.getBytesDownloaded( ) + channel.getFirstByteDelivered() self.__updateStepProgress(step) if not channel.isValid(): self.notify.warning("Failed to download %s" % (url)) elif not fileSpec.fullVerify(self.getPackageDir(), pathname=targetPathname, notify=self.notify): self.notify.warning( "After downloading, %s incorrect" % (Filename(fileSpec.filename).getBasename())) # This attempt failed. Maybe the original contents.xml # file is stale. Try re-downloading it now, just to be # sure. if self.host.redownloadContentsFile(self.http): # Yes! Go back and start over from the beginning. yield self.restartDownload return else: # Success! yield self.stepComplete return # Maybe the mirror is bad. Go back and try the next # mirror. # All attempts failed. Maybe the original contents.xml file # is stale. Try re-downloading it now, just to be sure. if self.host.redownloadContentsFile(self.http): # Yes! Go back and start over from the beginning. yield self.restartDownload return # All mirrors failed; the server (or the internet connection) # must be just fubar. yield self.stepFailed return
class DirectNewsFrame(DirectObject.DirectObject): TaskName = 'HtmlViewUpdateTask' TaskChainName = 'RedownladTaskChain' RedownloadTaskName = 'RedownloadNewsTask' NewsBaseDir = config.GetString('news-base-dir', '/httpNews') NewsStageDir = config.GetString('news-stage-dir', 'news') FrameDimensions = (-1.30666637421, 1.30666637421, -0.751666665077, 0.751666665077) notify = DirectNotifyGlobal.directNotify.newCategory('DirectNewsFrame') NewsIndexFilename = config.GetString('news-index-filename', 'http_news_index.txt') NewsOverHttp = config.GetBool('news-over-http', True) CacheIndexFilename = 'cache_index.txt' SectionIdents = ['hom', 'new', 'evt', 'tot', 'att', 'tnr'] def __init__(self, parent = aspect2d): DirectObject.DirectObject.__init__(self) self.accept('newsSnapshot', self.doSnapshot) self.active = False self.parent = parent self.issues = [] self.accept('newsChangeWeek', self.changeWeek) self.curIssueIndex = 0 self.strFilenames = None self.redownloadingNews = False self.startRedownload = datetime.datetime.now() self.endRedownload = datetime.datetime.now() self.load() self.percentDownloaded = 0.0 self.numIssuesExpected = 0 self.needsParseNews = True self.newsIndexEntries = [] if self.NewsOverHttp: self.redownloadNews() self.accept('newIssueOut', self.handleNewIssueOut) self.accept('clientCleanup', self.handleClientCleanup) return def parseNewsContent(self): if not self.needsParseNews: return self.needsParseNews = False result = False newsDir = self.findNewsDir() if newsDir: allHomeFiles = self.getAllHomeFilenames(newsDir) self.notify.debug('len allHomeFiles = %s' % len(allHomeFiles)) self.numIssuesExpected = len(allHomeFiles) if allHomeFiles: for myIssueIndex, oneHomeFile in enumerate(allHomeFiles): if type(oneHomeFile) == type(''): justFilename = oneHomeFile else: justFilename = oneHomeFile.getFilename().getBasename() self.notify.debug('parseNewContent %s' % justFilename) parts = justFilename.split('_') dateStr = parts[3] majorVer, minorVer = self.calcIssueVersion(dateStr) if majorVer == 1: oneIssue = IssueFrame.IssueFrame(self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames) elif majorVer == 2: oneIssue = IssueFrameV2.IssueFrameV2(self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames, self.newsIndexEntries) else: self.notify.warning('Dont know how to handle version %s, asuming v2' % majorVer) oneIssue = IssueFrameV2.IssueFrameV2(self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames, self.newsIndexEntries) oneIssue.hide() self.issues.append(oneIssue) if self.issues: self.issues[-1].show() self.curIssueIndex = len(self.issues) - 1 result = True if hasattr(base.cr, 'inGameNewsMgr') and base.cr.inGameNewsMgr: self.createdTime = base.cr.inGameNewsMgr.getLatestIssue() self.notify.debug('setting created time to latest issue %s' % self.createdTime) else: self.createdTime = base.cr.toontownTimeManager.getCurServerDateTime() self.notify.debug('setting created time cur server time %s' % self.createdTime) return result def getAllHomeFilenames(self, newsDir): self.notify.debug('getAllHomeFilenames') newsDirAsFile = vfs.getFile(Filename(newsDir)) fileList = newsDirAsFile.scanDirectory() fileNames = fileList.getFiles() #self.notify.debug('filenames=%s' % fileNames) homeFileNames = set([]) for name in fileNames: self.notify.debug('processing %s' % name) baseName = name.getFilename().getBasename() self.notify.debug('baseName=%s' % baseName) if 'hom1.' in baseName: homeFileNames.add(name) else: self.notify.debug('hom1. not in baseName') if not homeFileNames: self.notify.warning('couldnt find hom1. in %s' % fileNames) self.setErrorMessage(TTLocalizer.NewsPageNoIssues) return [] def fileCmp(fileA, fileB): return fileA.getFilename().compareTo(fileB.getFilename()) homeFileNames = list(homeFileNames) homeFileNames.sort(cmp=fileCmp) self.notify.debug('returned homeFileNames=%s' % homeFileNames) return homeFileNames def findNewsDir(self): if self.NewsOverHttp: return self.NewsStageDir searchPath = DSearchPath() if AppRunnerGlobal.appRunner: searchPath.appendDirectory(Filename.expandFrom('$TT_3_5_ROOT/phase_3.5/models/news')) else: basePath = os.path.expandvars('$TTMODELS') or './ttmodels' searchPath.appendDirectory(Filename.fromOsSpecific(basePath + '/built/' + self.NewsBaseDir)) searchPath.appendDirectory(Filename(self.NewsBaseDir)) pfile = Filename(self.NewsIndexFilename) found = vfs.resolveFilename(pfile, searchPath) if not found: self.notify.warning('findNewsDir - no path: %s' % self.NewsIndexFilename) self.setErrorMessage(TTLocalizer.NewsPageErrorDownloadingFile % self.NewsIndexFilename) return None self.notify.debug('found index file %s' % pfile) realDir = pfile.getDirname() return realDir def load(self): self.loadBackground() def loadBackground(self): upsellBackground = loader.loadModel('phase_3.5/models/gui/tt_m_gui_ign_newsStatusBackground') imageScaleX = self.FrameDimensions[1] - self.FrameDimensions[0] imageScaleY = self.FrameDimensions[3] - self.FrameDimensions[2] self.backFrame = DirectFrame(parent=self.parent, image=upsellBackground, image_scale=(imageScaleX, 1, imageScaleY), frameColor=(1, 1, 1, 0), frameSize=self.FrameDimensions, pos=(0, 0, 0), relief=DGG.FLAT, text=TTLocalizer.NewsPageDownloadingNews1, text_scale=0.06, text_pos=(0, -0.4)) def addDownloadingTextTask(self): self.removeDownloadingTextTask() task = taskMgr.doMethodLater(1, self.loadingTextTask, 'DirectNewsFrameDownloadingTextTask') task.startTime = globalClock.getFrameTime() self.loadingTextTask(task) def removeDownloadingTextTask(self): taskMgr.remove('DirectNewsFrameDownloadingTextTask') def loadMainPage(self): self.mainFrame = DirectFrame(parent=self.backFrame, frameSize=self.FrameDimensions, frameColor=(1, 0, 0, 1)) def activate(self): if hasattr(self, 'createdTime') and self.createdTime and self.NewsOverHttp and not self.redownloadingNews: self.active = False else: self.addDownloadingTextTask() if self.needsParseNews and not self.redownloadingNews: self.parseNewsContent() self.active = True def deactivate(self): self.removeDownloadingTextTask() self.active = False def unload(self): self.removeDownloadingTextTask() result = taskMgr.remove(self.RedownloadTaskName) self.ignore('newsSnapshot') self.ignore('newsChangeWeek') self.ignore('newIssueOut') self.ignore('clientCleanup') def handleClientCleanup(self): pass def doSnapshot(self): pass def changeWeek(self, issueIndex): if 0 <= issueIndex and issueIndex < len(self.issues): self.issues[self.curIssueIndex].hide() self.issues[issueIndex].show() self.curIssueIndex = issueIndex def loadingTextTask(self, task): timeIndex = int(globalClock.getFrameTime() - task.startTime) % 3 timeStrs = (TTLocalizer.NewsPageDownloadingNews0, TTLocalizer.NewsPageDownloadingNews1, TTLocalizer.NewsPageDownloadingNews2) textToDisplay = timeStrs[timeIndex] % int(self.percentDownloaded * 100) if self.backFrame['text'] != textToDisplay: if TTLocalizer.NewsPageDownloadingNewsSubstr in self.backFrame['text']: self.backFrame['text'] = textToDisplay return task.again def setErrorMessage(self, errText): self.backFrame['text'] = errText def redownloadNews(self): if self.redownloadingNews: self.notify.warning('averting potential crash redownloadNews called twice, just returning') return self.percentDownloaded = 0.0 self.notify.info('starting redownloadNews') self.startRedownload = datetime.datetime.now() self.redownloadingNews = True self.addDownloadingTextTask() for issue in self.issues: issue.destroy() self.issues = [] self.curIssueIndex = 0 self.strFilenames = None self.needsParseNews = True self.newsUrl = self.getInGameNewsUrl() self.newsDir = Filename(self.findNewsDir()) Filename(self.newsDir + '/.').makeDir() http = HTTPClient.getGlobalPtr() self.url = self.newsUrl + self.NewsIndexFilename self.ch = http.makeChannel(True) self.ch.beginGetDocument(self.url) self.rf = Ramfile() self.ch.downloadToRam(self.rf) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadIndexTask, self.RedownloadTaskName) return def downloadIndexTask(self, task): if self.ch.run(): return task.cont if not self.ch.isValid(): self.notify.warning('Unable to download %s' % self.url) self.redownloadingNews = False return task.done self.newsFiles = [] filename = self.rf.readline() while filename: filename = filename.strip() if filename: self.newsFiles.append(filename) filename = self.rf.readline() del self.rf self.newsFiles.sort() self.newsIndexEntries = list(self.newsFiles) self.notify.info('Server lists %s news files' % len(self.newsFiles)) self.notify.debug('self.newsIndexEntries=%s' % self.newsIndexEntries) self.readNewsCache() for basename in os.listdir(self.newsDir.toOsSpecific()): if basename != self.CacheIndexFilename and basename not in self.newsCache: junk = Filename(self.newsDir, basename) self.notify.info('Removing %s' % junk) junk.unlink() self.nextNewsFile = 0 return self.downloadNextFile(task) def downloadNextFile(self, task): while self.nextNewsFile < len(self.newsFiles) and 'aaver' in self.newsFiles[self.nextNewsFile]: self.nextNewsFile += 1 if self.nextNewsFile >= len(self.newsFiles): self.notify.info('Done downloading news.') self.percentDownloaded = 1 del self.newsFiles del self.nextNewsFile del self.newsUrl del self.newsDir del self.ch del self.url if hasattr(self, 'filename'): del self.filename self.redownloadingNews = False if self.active: self.parseNewsContent() return task.done self.percentDownloaded = float(self.nextNewsFile) / float(len(self.newsFiles)) self.filename = self.newsFiles[self.nextNewsFile] self.nextNewsFile += 1 self.url = self.newsUrl + self.filename localFilename = Filename(self.newsDir, self.filename) self.notify.info('testing for %s' % localFilename.getFullpath()) doc = DocumentSpec(self.url) if self.filename in self.newsCache: size, date = self.newsCache[self.filename] if date and localFilename.exists() and (size == 0 or localFilename.getFileSize() == size): doc.setDate(date) doc.setRequestMode(doc.RMNewer) self.ch.beginGetDocument(doc) self.ch.downloadToFile(localFilename) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadCurrentFileTask, self.RedownloadTaskName) def downloadCurrentFileTask(self, task): if self.ch.run(): return task.cont if self.ch.getStatusCode() == 304: self.notify.info('already cached: %s' % self.filename) return self.downloadNextFile(task) localFilename = Filename(self.newsDir, self.filename) if not self.ch.isValid(): self.notify.warning('Unable to download %s' % self.url) localFilename.unlink() if self.filename in self.newsCache: del self.newsCache[self.filename] self.saveNewsCache() return self.downloadNextFile(task) self.notify.info('downloaded %s' % self.filename) size = self.ch.getFileSize() doc = self.ch.getDocumentSpec() date = '' if doc.hasDate(): date = doc.getDate().getString() self.newsCache[self.filename] = (size, date) self.saveNewsCache() return self.downloadNextFile(task) def readNewsCache(self): cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename) self.newsCache = {} if cacheIndexFilename.isRegularFile(): file = open(cacheIndexFilename.toOsSpecific(), 'r') for line in file.readlines(): line = line.strip() keywords = line.split('\t') if len(keywords) == 3: filename, size, date = keywords if filename in self.newsFiles: try: size = int(size) except ValueError: size = 0 self.newsCache[filename] = (size, date) def saveNewsCache(self): cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename) try: file = open(cacheIndexFilename.toOsSpecific(), 'w') except IOError, e: self.notify.warning('error opening news cache file %s: %s' % (cacheIndexFilename, str(e))) return for filename, (size, date) in self.newsCache.items(): print >> file, '%s\t%s\t%s' % (filename, size, date)
def quickVerify(self, packageDir=None, pathname=None, notify=None, correctSelf=False): """ Performs a quick test to ensure the file has not been modified. This test is vulnerable to people maliciously attempting to fool the program (by setting datestamps etc.). if correctSelf is True, then any discrepency is corrected by updating the appropriate fields internally, making the assumption that the file on disk is the authoritative version. Returns true if it is intact, false if it is incorrect. If correctSelf is true, raises OSError if the self-update is impossible (for instance, because the file does not exist).""" if not pathname: pathname = Filename(packageDir, self.filename) try: st = os.stat(pathname.toOsSpecific()) except OSError: # If the file is missing, the file fails. if notify: notify.debug("file not found: %s" % (pathname)) if correctSelf: raise return False if st.st_size != self.size: # If the size is wrong, the file fails. if notify: notify.debug("size wrong: %s" % (pathname)) if correctSelf: self.__correctHash(packageDir, pathname, st, notify) return False if st.st_mtime == self.timestamp: # If the size is right and the timestamp is right, the # file passes. if notify: notify.debug("file ok: %s" % (pathname)) return True if notify: notify.debug("modification time wrong: %s" % (pathname)) # If the size is right but the timestamp is wrong, the file # soft-fails. We follow this up with a hash check. if not self.checkHash(packageDir, pathname, st): # Hard fail, the hash is wrong. if notify: notify.debug("hash check wrong: %s" % (pathname)) notify.debug(" found %s, expected %s" % (self.actualFile.hash, self.hash)) if correctSelf: self.__correctHash(packageDir, pathname, st, notify) return False if notify: notify.debug("hash check ok: %s" % (pathname)) # The hash is OK after all. Change the file's timestamp back # to what we expect it to be, so we can quick-verify it # successfully next time. if correctSelf: # Or update our own timestamp. self.__correctTimestamp(pathname, st, notify) return False else: self.__updateTimestamp(pathname, st) return True
def readContentsFile(self, tempFilename=None, freshDownload=False): """ Reads the contents.xml file for this particular host, once it has been downloaded into the indicated temporary file. Returns true on success, false if the contents file is not already on disk or is unreadable. If tempFilename is specified, it is the filename read, and it is copied the file into the standard location if it's not there already. If tempFilename is not specified, the standard filename is read if it is known. """ if not hasattr(core, 'TiXmlDocument'): return False if not tempFilename: if self.hostDir: # If the filename is not specified, we can infer it # if we already know our hostDir hostDir = self.hostDir else: # Otherwise, we have to guess the hostDir. hostDir = self.__determineHostDir(None, self.hostUrl) tempFilename = Filename(hostDir, 'contents.xml') doc = core.TiXmlDocument(tempFilename.toOsSpecific()) if not doc.LoadFile(): return False xcontents = doc.FirstChildElement('contents') if not xcontents: return False maxAge = xcontents.Attribute('max_age') if maxAge: try: maxAge = int(maxAge) except: maxAge = None if maxAge is None: # Default max_age if unspecified (see p3d_plugin.h). from direct.p3d.AppRunner import AppRunner maxAge = AppRunner.P3D_CONTENTS_DEFAULT_MAX_AGE # Get the latest possible expiration time, based on the max_age # indication. Any expiration time later than this is in error. now = int(time.time()) self.contentsExpiration = now + maxAge if freshDownload: self.contentsSpec.readHash(tempFilename) # Update the XML with the new download information. xorig = xcontents.FirstChildElement('orig') while xorig: xcontents.RemoveChild(xorig) xorig = xcontents.FirstChildElement('orig') xorig = core.TiXmlElement('orig') self.contentsSpec.storeXml(xorig) xorig.SetAttribute('expiration', str(self.contentsExpiration)) xcontents.InsertEndChild(xorig) else: # Read the download hash and expiration time from the XML. expiration = None xorig = xcontents.FirstChildElement('orig') if xorig: self.contentsSpec.loadXml(xorig) expiration = xorig.Attribute('expiration') if expiration: try: expiration = int(expiration) except: expiration = None if not self.contentsSpec.hash: self.contentsSpec.readHash(tempFilename) if expiration is not None: self.contentsExpiration = min(self.contentsExpiration, expiration) # Look for our own entry in the hosts table. if self.hostUrl: self.__findHostXml(xcontents) else: assert self.hostDir self.__findHostXmlForHostDir(xcontents) if self.rootDir and not self.hostDir: self.hostDir = self.__determineHostDir(None, self.hostUrl) # Get the list of packages available for download and/or import. xpackage = xcontents.FirstChildElement('package') while xpackage: name = xpackage.Attribute('name') platform = xpackage.Attribute('platform') version = xpackage.Attribute('version') try: solo = int(xpackage.Attribute('solo') or '') except ValueError: solo = False try: perPlatform = int(xpackage.Attribute('per_platform') or '') except ValueError: perPlatform = False package = self.__makePackage(name, platform, version, solo, perPlatform) package.descFile = FileSpec() package.descFile.loadXml(xpackage) package.setupFilenames() package.importDescFile = None ximport = xpackage.FirstChildElement('import') if ximport: package.importDescFile = FileSpec() package.importDescFile.loadXml(ximport) xpackage = xpackage.NextSiblingElement('package') self.hasContentsFile = True # Now save the contents.xml file into the standard location. if self.appRunner and self.appRunner.verifyContents != self.appRunner.P3DVCNever: assert self.hostDir filename = Filename(self.hostDir, 'contents.xml') filename.makeDir() if freshDownload: doc.SaveFile(filename.toOsSpecific()) else: if filename != tempFilename: tempFilename.copyTo(filename) return True
def quickVerify(self, packageDir = None, pathname = None, notify = None, correctSelf = False): """ Performs a quick test to ensure the file has not been modified. This test is vulnerable to people maliciously attempting to fool the program (by setting datestamps etc.). if correctSelf is True, then any discrepency is corrected by updating the appropriate fields internally, making the assumption that the file on disk is the authoritative version. Returns true if it is intact, false if it is incorrect. If correctSelf is true, raises OSError if the self-update is impossible (for instance, because the file does not exist).""" if not pathname: pathname = Filename(packageDir, self.filename) try: st = os.stat(pathname.toOsSpecific()) except OSError: # If the file is missing, the file fails. if notify: notify.debug("file not found: %s" % (pathname)) if correctSelf: raise return False if st.st_size != self.size: # If the size is wrong, the file fails. if notify: notify.debug("size wrong: %s" % (pathname)) if correctSelf: self.__correctHash(packageDir, pathname, st, notify) return False if int(st.st_mtime) == self.timestamp: # If the size is right and the timestamp is right, the # file passes. if notify: notify.debug("file ok: %s" % (pathname)) return True if notify: notify.debug("modification time wrong: %s" % (pathname)) # If the size is right but the timestamp is wrong, the file # soft-fails. We follow this up with a hash check. if not self.checkHash(packageDir, pathname, st): # Hard fail, the hash is wrong. if notify: notify.debug("hash check wrong: %s" % (pathname)) notify.debug(" found %s, expected %s" % (self.actualFile.hash, self.hash)) if correctSelf: self.__correctHash(packageDir, pathname, st, notify) return False if notify: notify.debug("hash check ok: %s" % (pathname)) # The hash is OK after all. Change the file's timestamp back # to what we expect it to be, so we can quick-verify it # successfully next time. if correctSelf: # Or update our own timestamp. self.__correctTimestamp(pathname, st, notify) return False else: self.__updateTimestamp(pathname, st) return True