import os import posixpath import json from panda3d.core import VirtualFileSystem class PackageNotFound(FileNotFoundError): pass class PackageMetaNotFound(FileNotFoundError): pass class PackageInvalid(FileNotFoundError): pass class PackageDuplicate(FileNotFoundError): pass class Package: def __init__(self, name, vfs_dir): self.name = name self.vfs_dir = vfs_dir class Filesystem: def __init__(self): self.package_list = [] self.package_map = {} self.vfs = VirtualFileSystem.getGlobalPtr() self.include('assets/') self.mdl_missing = loader.loadModel('/main-assets/models/missing.glb') self.mdl_missing.setTexture(loader.loadTexture('/main-assets/textures/missing_mdl.png')) self.tex_missing = loader.loadTexture('/main-assets/textures/missing_tex.png') def include(self, path): if not os.path.exists(path): raise PackageNotFound(path) gamepkg_path = os.path.join(path, 'gamepackage.json') if not os.path.exists(gamepkg_path): raise PackageMetaNotFound(path) meta = json.load(open(gamepkg_path)) if 'name' not in meta: raise PackageInvalid(path) if meta['name'] in self.package_map: raise PackageDuplicate(meta['name']) vfs_path = f'/{meta["name"]}' vfs.mount(path, f'/{meta["name"]}', 0) new_package = Package(meta["name"], vfs_path) self.package_map[meta['name']] = new_package self.package_list.insert(0, new_package) def find_texture(self, tex_path): try: if tex_path[0:2] == '$/': for package in self.package_list: path = posixpath.join('/', package.name, 'textures', tex_path[2:]) if self.vfs.exists(path): return loader.loadTexture(path) return self.tex_missing else: resource_path = model_path.split('/') path = posixpath.join('/', resource_path[0], 'textures', '/'.join(resource_path[1:])) return loader.loadTexture(path) except IOError: return self.tex_missing def find_model(self, model_path): try: if model_path[0:2] == '$/': for package in self.package_list: path = posixpath.join('/', package.name, 'models', model_path[2:]) if self.vfs.exists(path): return loader.loadModel(path) return self.mdl_missing else: resource_path = model_path.split('/') path = posixpath.join('/', resource_path[0], 'models', '/'.join(resource_path[1:])) return loader.loadModel(path) except IOError: return self.mdl_missing