Panda3D Manual: Creating Multifiles
<<prev | top | next>> |
Multifiles archives are archive files that store game resources. Think of it as a gaint zip file that stores optionally zips and encrypts your data files, but does not need to be extracted. ## The multify program The multify console program creates such files. You can get information about the commandline parameters by running multify with the `-h` option. This is how program describes itself:
    Usage: multify -[c|r|u|t|x] -f <multifile_name> [options] <subfile_name> ...
multify is used to store and extract files from a Panda Multifile. This is similar to a tar or zip file in that it is an archive file that contains a number of subfiles that may later be extracted. Panda's VirtualFileSystem is capable of mounting Multifiles for direct access to the subfiles contained within without having to extract them out to independent files first. The command-line options for multify are designed to be similar to those for tar, the traditional Unix archiver utility. If you want to load assets from a Multifile directly, you can "mount" it into the virtual file system:
    from pandac.PandaModules import VirtualFileSystem, Filename
    vfs = VirtualFileSystem.getGlobalPtr()
    vfs.mount(Filename("foo.mf"), ".", VirtualFileSystem.MFReadOnly)
If you are having problems loading form multifiles you can list the complete contents of your .mf file with a command like:
    mutify -tvf mymultifile.mf
Doing a sanity inspection like this can be useful to ensure that your assets are in the right place within the multifile. ## Multifile objects The Multifile class is designed for opening, reading and writing multifiles. You can open a new multifile by creating an instance of the class and calling the `openRead` method:
    from pandac.PandaModules import Multifile
    mf = Multifile()
    mf.openRead("foo.mf")
The `openRead` method opens the multifile as read-only. If you want to make changes to it and write it back to disk, you will need to use the `openReadWrite` method. Also, there exists `openWrite` to create a new multifile. If you have made important structural changes to a Multifile, it is recommended to rewrite the multifile using the `repack()` method. (This won't work if you've opened it using `openRead`.) If you are uncertain about whether it has become suboptimal, you can call `needsRepack()` which returns True if the Multifile is suboptimal and should be repacked. To write it back to disk, you can use the `flush()` method which flushes the changes you've made to the multifile back to disk, or the `close()` method if you're done with the file. To mount Multifile objects into the VirtualFileSystem without writing them to disk first, here's an example on how to mount them:
    yourMF = Multifile()
    #... now do something with yourMF

    vfs = VirtualFileSystem.getGlobalPtr()
    vfs.mount(yourMF, ".", VirtualFileSystem.MFReadOnly)
## Subfiles Files that are added to a multifile are called subfiles. You can add existing files to a multifile object using the `addSubfile` function. This function takes three arguments: the target filename, the existing source file and the compression level (1-9). There is also `updateSubfile`, which does the same thing but if the file already exists, only updates it if the content is different. There are several other methods which operate on subfiles, which you can find in the API Reference. Here are a few examples of working with subfiles:
    # Add an existing file with compression level 6
    m = Multifile()
    m.openWrite("foo.mf")
    m.addSubfile("bar.txt", Filename("/tmp/bar.txt"), 6)
    m.repack()
    m.close()

    # Open a multifile and replace a file
    m = Multifile()
    m.openReadWrite("foo.mf")
    m.updateSubfile("bar.txt", Filename("/tmp/bar2.txt"), 9)
    m.repack()
    m.close()

    # Open a multifile and extract all files smaller than 3kb
    m = Multifile()
    m.openRead("foo.mf")
    for i in range(m.getNumSubfiles):
      if m.getSubfileLength() < 3 * 1024:
        m.extractSubfile(i, "/tmp/" + m.getSubfileName())

    # Find, print and remove a file named bar.txt
    barIdx = m.findSubfile("bar.txt")
    if barIdx != -1:
      # It returns -1 if it doesn't exist
      print m.readSubfile(barIdx)
      m.removeSubfile(barIdx)
    m.close()
## Encryption Multifiles can also encrypt your files with a password. To do so, you need to set the encryption flag and password using the `setEncryptionFlag` and `setEncryptionPassword` methods, before adding, extracting or reading multifiles. For instance, this code creates a multifile and adds an encrypted file to it:
    m = Multifile()
    m.openWrite("foo.mf")
    m.setEncryptionFlag(True)
    m.setEncryptionPassword("foobar")
    m.addSubfile("bar.txt", Filename("/tmp/bar.txt"), 1)
    m.repack()
    m.close()
You can read encrypted multifiles the same way:
    m = Multifile()
    m.openWrite("foo.mf")
    m.setEncryptionFlag(True)
    m.setEncryptionPassword("foobar")
    m.readSubfile("bar.txt")
You can check if a certain subfile is encrypted or not using the `isSubfileEncrypted` method, which takes the subfile index as parameter. It is possible to have a multifile where different subfiles have different encryption, but you will not be able to mount it with the VirtualFileSystem or use it with the multify tool. To mount an encrypted file using the VirtualFileSystem, pass the password as parameter to the `mount` method:
    from pandac.PandaModules import VirtualFileSystem, Filename
    vfs = VirtualFileSystem.getGlobalPtr()
    vfs.mount(Filename("foo.mf"), ".", vfs.MFReadOnly, "foobar")
To use encryption with the multify tool, run it with the `-e` option, which will prompt for a password on the command line. Alternatively, if you also specify the `-p "password"` option, you can specify it in the command instead of typing it at the prompt.
<<prev | top | next>> |