Package resources¶
SimVX accepts game assets (textures, audio, meshes, glTF scenes, config
files) as filesystem paths or as Python-package handles. An asset that ships
inside a package is named with Resource(package, name), which resolves to a file through
importlib.resources.
Why importlib.resources?¶
One naming scheme. Assets live in Python packages (a directory with an
__init__.py). The sameResource(package, name)handle works whether the package is a source checkout, installed from a wheel, or bundled into a web export.Refactor-safe. Renaming a package via your IDE/LSP keeps all
Resource("my_game.assets", ...)references in sync: no separate UID database to migrate.No sidecar files and no manifest to regenerate: the Python module graph is the manifest.
No code generation. Scenes are
.pyfiles and asset references are ordinary Python objects.
The Resource helper¶
from simvx.core import Resource
helmet = Resource("my_game.assets.models", "helmet.gltf")
helmet.path # PosixPath('/.../my_game/assets/models/helmet.gltf')
helmet.read_bytes() # b'...'
with helmet.open() as fh:
data = fh.read()
Resource(package, name) is lazy: construction never touches the
filesystem. Resolution happens on first access of .path /
.read_bytes() / .open(). Errors are strict by default:
Failure |
Exception |
|---|---|
Empty package or name |
|
Package cannot be imported |
|
File missing inside package |
|
Resource instances are equal by (package, name) and hashable, so they
work as dict keys and in sets.
Marking a directory as a resource package¶
A directory becomes a Python package, and therefore a Resource lookup
target: by adding an empty __init__.py:
my_game/
__init__.py
main.py
assets/
__init__.py <-- makes "my_game.assets" importable
models/
__init__.py <-- makes "my_game.assets.models" importable
helmet.gltf
helmet.bin
Then anywhere in your game:
from simvx.core import Resource
HELMET = Resource("my_game.assets.models", "helmet.gltf")
Example: a glTF model¶
from simvx.core import Resource
from simvx.graphics import import_gltf
HELMET = Resource("my_game.assets.models", "helmet.gltf")
def on_ready(self):
self.add_child(import_gltf(str(HELMET.path)))
Resource.path is a real file on disk, so the glTF loader finds the sibling .bin and texture
files through the relative URIs inside the glTF.
Filesystem paths¶
For assets that don’t ship inside a Python package (e.g. user-supplied
files, content downloaded at runtime, project-relative working copies),
pass a str or pathlib.Path:
from pathlib import Path
from simvx.core import AudioClip, Mesh
AudioClip("music/theme.ogg") # relative to the working directory
AudioClip(Path.home() / "tracks" / "x.ogg") # absolute
Mesh.from_obj(Path(__file__).parent / "models" / "ship.obj") # beside this file
Strings are filesystem paths only: there is no URI scheme to parse and no ambiguity between “package” and “path” syntax.
Accepted source types¶
AudioClip, Mesh.from_obj, and resolve_asset_path all accept the same
union:
Source |
When to use |
|---|---|
|
Filesystem path (absolute or project-root-relative). |
|
Asset shipped inside a Python package. |
|
Raw |
Anything else raises TypeError.