Loading modules from multifiles

I’m sure this has been addressed before, but searching for it turned up nothing relevant in the forums.

I’ve been using multifiles to store my game content to great success, mounting them as virtual file systems. Recently though I thought to store my custom modules in them also. However, panda seems to not like loading them from the VFS at all, claiming it can’t find them when they are most certainly in the file.

Is there any particular reason that panda refuses to load modules from the VFS?

Hm, maybe this excerpt from a post by drwr will help you:

Right, hmm, well while I’m certain this is what I’m after, simply adding

from direct.showbase import VFSImporter
VFSImporter.register()

to the top of my code does nothing at all. I’ve read through the VFSImporter.py but it is offering me no hints on usage. Is the VFSImporter a replacement for VirtualFileSystem?

How exactly does one use this? I attempted it like this:

from pandac.PandaModules import *
from direct.showbase import VFSImporter

vfs = VirtualFileSystem.getGlobalPtr()
vfs.mount(Filename('foobar.mf'), '.', VirtualFileSystem.MFReadOnly)
VFSImporter.register()

This seems wrong, cause it doesn’t work. Any specific hints on usage? Nothing I’ve tried does anything.

You still need to add the location of the module to sys.path and then import it using the “import” statement. And I think you need to register the importer even before you open the multifile.

Maybe something like this (untested):

from pandac.PandaModules import *
from direct.showbase import VFSImporter
VFSImporter.register()

vfs = VirtualFileSystem.getGlobalPtr()
vfs.mount(Filename('foobar.mf'), '/mf', VirtualFileSystem.MFReadOnly)
sys.path.append("/mf")
import yourmodule
 

Huh, well that seemed to do it, registering before the vfs mount. Seems backwards to me, I’d think you’d register the vfs after it’s mounted, but there you go. Thanks for the input. Consider that code you posted as tested, cause I did, and it works.

Actually, I don’t think the order of the call to register() vs. vfs.mount() matters. The key piece that you didn’t mention in your earlier examples is adding the directory to sys.path.

Note that VFSImporter.register() isn’t registering any particular mounted multifile; it’s registering itself on the Python import hooks. And the name “vfs” stands for “virtual file system”, which refers to the whole directory system, not just any one particular mounted multifile.

David

What is the syntax for specifying a file to mount on a remote machine?

What do you mean?

David

I should have asked what pathname string would I specify in the above example if “foobar.mf” existed on a remote machine named “foobar”.

The string “//foobar:/foobar.mf” for example doesnt work.

Can only local multifiles be mounted?

The Panda Filename convention follows the Unix convention for naming remote files, which is like “/hosts/foobar/foobar.mf”. Try that.

David

Hi David,

if vfs.mount(Filename('/c/projects/vfs/foobar.mf'), '/mf', VirtualFileSystem.MFReadOnly):

works fine. As a sanity check I tried:

if vfs.mount(Filename('/localhost/c/projects/vfs/foobar.mf'), '/mf', VirtualFileSystem.MFReadOnly):

and

if vfs.mount(Filename('/127.0.0.1/c/projects/vfs/foobar.mf'), '/mf', VirtualFileSystem.MFReadOnly):

both invocations fail to mount. My test machine is running Panda 1.6.2 on Windows XP.

No, you misunderstood. The string would be “/hosts/localhost/c/projects/vfs/foobar.mf”.

The “/hosts/” prefix is literal, and is the keyword that indicates that the next name is the name of the remote computer, followed by the name of the remote file. This is the Unix convention for remote filenames.

David

Tried that too. Same result. The following strings also fail to mount.

‘/hosts/127.0.0.1/c/projects/vfs/foobar.mf’
‘/hosts/192.168.1.202/c/projects/vfs/foobar.mf’
‘/hosts/monaco1/c/projects/vfs/foobar.mf’

Are you sure those volumes have been exported (made public) from their respective machines?

Do you really need the c: prefix on the filename? I think Windows usually doesn’t want that, right? It exports a particular directory under the volume name you give it, which isn’t going to be the same as the drive letter.

Can you type “\127.0.0.1\c:\projects\vfs” on the run command and open up the folder? If you can’t, then Panda isn’t going to be able to, either.

If that does work, though, then try putting the drive letter colon in the filename: ‘/hosts/127.0.0.1/c:/projects/vfs/foobar.mf’

But, really, this is kind of weird. Why not just download the file in the first place? It will be a lot faster to access.

David

doh! I forgot to remove the drive letter from the string.

I am planning on mounting the multifiles on a server for development purposes.

as always, Thanks David!

Can a multifile be mounted from a webserver? If so, can someone show and example?

Never mind a multifile, you can mount a whole directory structure from a webserver. If your webserver hosts:

myserver/mydir/models/myfile.bam
myserver/mydir/maps/mytexture.png

and so on, then you can put this in your Config.prc:

vfs-mount-url http://myserver/mydir /mydir
model-path /mydir

or, equivalently, write this Python code at startup:

vfs.mount(VirtualFileMountHTTP('http://myserver/mydir'), '/mydir', 0)
getModelPath().appendDirectory('/mydir')

and then you can load models like this in your Python code:

model = loader.loadModel('models/myfile.bam')
texture = loader.loadTexture('maps/mytexture.png')

It might be possible to mount a packed multifile, but that would be inefficient, since HTTP isn’t well-suited for pulling out pieces of a large file at a time. It works much better for loading individual files like this. So, just unpack your multifile into your server’s host directory.

David