示例#1
0
    def dump(self, f, showContents=True, keyColumnWidth=25):
        """Dump a message in human readable form to the stream 'f'."""
        from BZFlag import Protocol
        from StringIO import StringIO

        name = self.__class__.__name__

        # If the message was received with Network.Socket.readMessage,
        # we can determine where it came from by its fromModule attribute
        direction = ''
        try:
            from BZFlag.Protocol import FromServer, ToServer
            if self.fromModule == ToServer:
                direction = "-->"
            elif self.fromModule == FromServer:
                direction = "<--"
        except AttributeError:
            pass

        f.write("%s %s\n" % (direction, name))
        if not showContents:
            return

        # Attributes for us to ignore. These are generally things we annotate the message
        # with later. Note that this isn't a list of all such annotations- most notably,
        # 'protocol' is omitted since it's very useful to have in message dumps.
        ignoreList = ('eventLoop', 'socket', 'header', 'fromModule', 'fromAddress', 'client')

        # Recursively build a list of (key,value) tuples that will be displayed
        # to represent a message. This handles traversing into substructures
        # like FlagUpdate.
        def buildKeys(object, prefix=""):
            keys = object.__dict__.keys()
            keys.sort()
            lst = []
            for key in keys:
                if key[0] != '_' and not key in ignoreList:
                    value = object.__dict__[key]
                    if isinstance(value, Protocol.Struct):
                        lst.extend(buildKeys(value, prefix + key + "."))
                    else:
                        lst.append((prefix + key, value))
            return lst

        for (key, value) in buildKeys(self):
            if key == 'data':
                # Special decoding for 'data' members- do a hex dump
                d = StringIO()
                Util.hexDump(StringIO(value), d)
                value = ("%d bytes\n" % len(value)) + d.getvalue()
            else:
                # Let python decode everything else
                value = repr(value)

            # Handle printing multiline values properly
            lines = value.split("\n")
            print ("%%%ss: %%s" % keyColumnWidth) % (key, lines[0])
            for line in lines[1:]:
                if line:
                    f.write(" " * (keyColumnWidth + 2) + line + "\n")
示例#2
0
 def loadDataFile(self, name):
     """Load the texture from a file in our data directory.
        The main reason for this function to exist is so a texture can
        be pickled without hardcoding the data path in the pickle.
        """
     self.loadImage(Image.open(Util.dataFile(name)))
     self.loader = ('loadDataFile', name)
     self.name = name
示例#3
0
 def __init__(self, name, sizes=defaultSizes):
     filename = Util.dataFile(name)
     pygame.font.init()
     self.sizes = {}
     self.sortedSizes = sizes
     self.sortedSizes.sort()
     for size in sizes:
         self.sizes[size] = RenderedFont(filename, size)
示例#4
0
    def __init__(self, name):
        self.encoding = 'utf8'
        self.meshes = {}

        self.parseStack = []
        self.namespace = {}
        f = Util.autoFile(name)
        self.parse(f)
        f.close()
        for node in self.parseStack:
            self.extractMeshes(node, ())
        del self.parseStack
        del self.namespace
示例#5
0
def Heightmap(name,
              size          = Scale.WorldSize,
              wallHeight    = Scale.WallHeight,
              boxHeight     = 20.0 * Scale.MuzzleHeight,
              ):
    """
    Uses the given image file to make a heightmapped world.
    This is very silly and nobody should use this except
    as an example and a proof-of-concept.
    Requires PIL.

    Positional arguments:
        name : File or URI containing the heightmap, in any format PIL supports

    Keyword arguments:
        size       : Distance along each side of the generated square world
        wallHeight : Height of the world's walls
        boxHeight  : Maximum box height, corresponding to a fully white pixel 
    """
    import Image
    f = Util.autoFile(name, "rb")
    img = Image.open(f).convert("L")   # Convert to grayscale
    w = World()
    w.erase()
    w.storeSkeletonHeader(size=size, wallHeight=wallHeight)

    # For now just output a box per nonzero pixel. If I expected
    # anyone to actually use this I'd make it combine rectangular
    # regions of the same pixel value into larger boxes.
    for y in xrange(img.size[1]):
        for x in xrange(img.size[0]):
            p = img.getpixel((x,y))
            if p:
                w.storeBlock(WorldObjects.Box(
                    center = ( (float(x) / img.size[0] - 0.5) * size,
                              -(float(y) / img.size[1] - 0.5) * size,
                               0),
                    size   = (size / img.size[0],
                              size / img.size[1],
                              p / 255.0 * boxHeight),
                    angle  = 0))
    
    w.storeSkeletonFooter()    
    w.postprocess()
    f.close()
    return w
示例#6
0
def Binary(name):
    """
    Load a world from a binary file. This is the world format used in
    transit from server to client, and used in the client's world cache.

    Positional arguments:
        name : File or URI containing the binary world
    """
    from BZFlag.Protocol import Common
    
    blockDict = Common.getMessageDict(WorldObjects)
    f = Util.autoFile(name)
    w = World()
    w.erase()
    while 1:
        # Read the block header
        header = WorldObjects.BlockHeader()
        packedHeader = f.read(header.getSize())
        if len(packedHeader) < header.getSize():
            raise Errors.ProtocolError("Premature end of binary world data")
        header.unmarshall(packedHeader)

        # Look up the block type and instantiate it
        try:
            block = blockDict[header.id]()
        except KeyError:
            raise Errors.ProtocolError(
                "Unknown block type 0x%04X in binary world data" % header.id)

        # Read the block body
        packedBody = f.read(block.getSize() - len(packedHeader))
        if len(packedBody) < (block.getSize() - len(packedHeader)):
            raise Errors.ProtocolError("Incomplete block in binary world data")
        block.unmarshall(packedHeader + packedBody)
        w.storeBlock(block)

        # We're done if this was the EndOfData block
        if isinstance(block, WorldObjects.EndOfData):
            break
    w.postprocess()
    return w
示例#7
0
def getMessageDict(module):
    """Return a dictionary mapping message IDs to message classes,
       given a module containing Message subclasses.
       """
    return Util.getSubclassDict(module, Message, 'messageId')
示例#8
0
parser = optik.OptionParser(usage = "usage: %prog [options] worlds")
parser.add_option("-o", "--output", metavar="FILE",
                  help="Sets the file or directory name to output thumbnails to.")
parser.add_option("-s", "--size", metavar="WIDTHxHEIGHT",
                  help="Sets the thumbnail size. Default is 160x160.", default="160x160")
parser.add_option("-i", "--index", action="store_true",
                  help="Generates an index of world files to the directory provided with -o.")
parser.add_option("-f", "--format", metavar="EXTENSION",
                  help="Sets the format, specified in the form of a file extension name, " +
                  "of the images to generate when an explicit filename is not given. Default is 'png'.", default='png')
parser.add_option("-a", "--oversample", metavar="AMOUNT",
                  help="Sets the amount of oversampling. Higher numbers will produce smoother images " +
                  "with thinner borders, but will require much more memory and CPU time. Default is 3.", default=3)
parser.add_option("-t", "--template", metavar="FILE",
                  help="Sets the template file to use for producing index output. Default is " +
                  "'worldindex.html' in the data directory.", default=Util.dataFile('worldindex.html'))
parser.add_option("-n", "--index-name", metavar="FILE", dest="indexName",
                  help="Sets the name of the index file to produce in the output directory. Default is 'index.html'.",
                  default="index.html")
(options, args) = parser.parse_args()

if len(args) == 0:
    parser.error("One or more world filenames must be specified on the command line.")
if len(args) > 1 and options.output and not os.path.isdir(options.output):
    parser.error("An output directory must be specified for multiple input files, not an output file.")
if options.index and options.output and not os.path.isdir(options.output):
    parser.error("An output directory must be specified for indexing mode, not an output file.")

size = map(int, options.size.split("x"))
oversample = int(options.oversample)
worlds = []
示例#9
0
def getDict():
    """Return a dictionary mapping flag abbreviations to flag classes"""
    import BZFlag.Flag.List
    return Util.getSubclassDict(BZFlag.Flag.List, FlagBase, 'abbreviation')
示例#10
0
def Text(name,
         size       = Scale.WorldSize,
         wallHeight = Scale.WallHeight,
         ):
    """
    Load a world from a text file. This is the default world format.

    Positional arguments:
        name : File or URI containing the world

    Keyword arguments:
        size       : Default distance along each side of the generated square world
        wallHeight : Height of the world's walls
    """
    import re
    
    f = Util.autoFile(name)
    w = World()
    section = None
    sectionDict = Util.getSubclassDict(WorldObjects, WorldObjects.WorldObject,
                                       'textName', 'textSectionDict')

    # We won't actually add the objects to the world until later,
    # since we need to start the world out with walls and a game style
    # block, but we might get the information needed for those at any
    # point in the file.
    w.erase()
    blocks = []
        
    for line in f:
        # If this is a kludge used by map editors to store extra
        # attributes. Don't process any comments on the line.
        if not line.startswith("#!"):
            line = re.sub("#.*", "", line)
        line = line.strip()
        if line:
            if section:
                # We're inside a section. Accumulate lines until 'end'
                sectionLines.append(line)
                if line == 'end':
                    # Done with this section, process it.

                    if section == 'world':
                        # World information
                        for line in sectionLines:
                            tokens = re.split("\s+", line)
                            keyword = tokens[0].lower()
                            args = tokens[1:]
                            if keyword == 'size':
                                size = int(args[0])

                    else:
                        # Assume all other sections are world objects
                        try:
                            cls = sectionDict[section]
                        except KeyError:
                            raise Errors.ProtocolError(
                                "World file contains unknown section type '%s'" % section)
                        inst = cls()
                        inst.textRead(sectionLines)
                        blocks.append(inst)
                        
                    section = None
            elif not line.startswith("#!"):
                # We're beginning a section
                section = line.lower()
                if section.find(" ") >= 0:
                    raise Errors.ProtocolError("Unexpected whitespace within section name")
                sectionLines = []

    if section:
        raise Errors.ProtocolError("World file has unterminated '%s' section" % section)

    # Now store all the blocks in our world
    w.storeSkeletonHeader(size, wallHeight)
    for block in blocks:
        w.storeBlock(block)
    w.storeSkeletonFooter()
    w.postprocess()
    return w
示例#11
0
def load(name):
    from BZFlag import Util
    return defaultCache.load(Util.dataFile(name))