Example #1
0
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)
Example #2
0
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)
Example #3
0
    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
Example #4
0
    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
Example #5
0
 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
Example #6
0
 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()
Example #7
0
    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
Example #8
0
    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
Example #9
0
    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
Example #10
0
    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)
Example #11
0
    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
Example #12
0
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)
Example #14
0
    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)
Example #15
0
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())
Example #16
0
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())
Example #17
0
    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()
Example #18
0
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())
Example #19
0
    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
Example #20
0
    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)
Example #21
0
    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)
Example #22
0
    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)
Example #23
0
    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)
Example #24
0
    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
Example #25
0
    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
Example #26
0
    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)
Example #27
0
    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)
Example #28
0
    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
Example #29
0
    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
Example #30
0
    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)
Example #31
0
    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)
Example #32
0
    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)
Example #33
0
    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
Example #34
0
    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)
Example #35
0
    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
Example #36
0
    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
Example #37
0
    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
Example #38
0
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)
Example #39
0
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
Example #40
0
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
Example #41
0
    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
Example #42
0
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()
Example #43
0
    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
Example #44
0
    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
Example #45
0
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)
Example #46
0
    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
Example #47
0
    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
Example #48
0
    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)
Example #49
0
    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