You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
.gma, .vpk, .bsp, .mdl (with its .vvd / .vtx), .smd
What makes these files?
Garry's Mod and other Source engine games and tools (gmad, Valve's vpk tool, Hammer/VBSP, studiomdl, Crowbar, Blender Source Tools)
Who works with these files?
Game modders (Garry's Mod and other Source engine games)
What should Filee convert them to?
GMA <-> folder/ZIP; VPK and BSP (packed files) -> folder/ZIP; MDL -> OBJ/GLB/STL (with its VTF textures) and SMD; SMD <-> OBJ/GLB
Anything else?
Follow-up to #1478 / #1483 (VTF). These are the other files Garry's Mod modders deal with every day. Today each needs its own tool (gmad, GCFScape, Crowbar, VIDE…), most of them Windows-only and unmaintained.
I'm already working on a pull request that adds them all at once, one commit per format, and will link it here:
GMA (Garry's Mod addon, Workshop): unpack to a folder or ZIP, and pack a folder back into a .gma as gmad does. That means addon.json for the title, type and tags, plus gmad's whitelist and ignore list.
VPK (Valve pak, _dir.vpk with its _000.vpk… parts): unpack to a folder or ZIP.
BSP (Source map): unpack the files packed into the map (the pakfile lump: custom textures, models, sounds) to a folder or ZIP.
MDL (Source model, read with its .vvd and .dx90.vtx): to OBJ, GLB, STL and the other 3D formats as a static mesh in its bind pose. The textures are found automatically through the VMT/VTF files in the addon's materials/ folder, using the VTF reader from feat(image): read and write Valve textures (VTF) for Garry's Mod and … #1483.
SMD (Valve's studiomdl source format): MDL → SMD as a reference mesh with skeleton and weights; other models ↔ SMD as static props.
All of it in managed code, with no new packages. Open-source references for the layouts: Facepunch/gmad, srctools, SourceIO and Crowbar.
Protection
These files aren't encrypted or copy-protected (DRM), and I can open them without a password.
Thanks, @ltsammy, and thanks again for VTF (#1483). These fit Filee well: the layouts are known from open-source tools, no new package is needed, and today each file needs its own, mostly Windows-only tool.
A few things before the PR goes up:
Smaller PRs, one at a time. Five formats in one PR is a lot to review at once. Could you split it? (1) unpacking GMA, VPK and BSP, (2) packing a folder into a GMA, (3) MDL and SMD. One commit per format inside each is fine.
Treat every file as hostile. Names inside a GMA, VPK or BSP pakfile must not escape the output folder (.., absolute paths, drive letters). Cap entry counts, entry sizes and the total unpacked size like the other archive readers do. MDL, VVD and VTX offsets and counts need bounds checks before anything is allocated.
Our own code. Use gmad, srctools, SourceIO and Crowbar to learn the layouts, but write the readers yourself rather than porting their code, so no other project's licence comes along with it.
VPK parts. A _dir.vpk reads its _000.vpk… parts from the same folder. Dropping a part file on its own should give a clear message, not a broken archive.
Donut and schema. Packing a folder into a GMA would sit on the Folders donut. If that, or anything else, needs a donut slot or a settings schema step (as VTF did), please say here first where it would go.
Thanks! I'll split it into three PRs, one after the other, with one commit per format in each: (1) unpacking GMA, VPK and BSP, (2) packing a folder into a GMA, (3) MDL and SMD.
On your points:
Hostile files:
Every name from a GMA, VPK or BSP pakfile goes through ArchiveSafety.ResolveEntryPath, so .., absolute paths, drive letters and characters Windows doesn't allow never leave the output folder.
Entry counts are capped at ArchiveSafety.MaxEntries, and names inside the lists at 4 KB.
The total declared size goes through EnsureRoom before anything is written.
Each entry is copied with CopyLimited at its declared size, then its length and CRC are checked.
The BSP pakfile is copied out and goes through the same 7-Zip listing checks as any ZIP.
MDL, VVD and VTX are each capped at 256 MB. Every count is checked against a limit and every offset against the file length before it is used or anything is allocated.
Own code: the readers and writers are written from the layouts. gmad, srctools, SourceIO and Crowbar were only used to learn them, and no code is ported.
VPK parts:_dir.vpk reads its parts from its own folder. A part dropped on its own gives "… is part 003 of a Valve pak; unpack pak01_dir.vpk, which lists its files." A missing part is named in the error.
Donut and schema, one schema step per PR, numbered when it's its turn. No donut slots anywhere:
Unpacking:gma (read-only in this PR), vpk and bsp go in the Archive category, Games field, specialist grade. The schema step only lets .gma, .vpk and .bsp learn the archives donut, as .vtf learned the images donut, with custom claims left alone. The donut's existing Extract / ZIP / 7Z slots work on them unchanged.
Packing:gma becomes writable, and a "GMA" preset goes in the palette after MRPACK, like the Minecraft and Modrinth packs. The schema step only adds that preset to existing libraries. I'd leave it off the Folders donut, because that donut is for everyone and the Games field is off in a new install. Anyone who wants it there can add it. If you'd rather have it on the Folders donut's back face, tell me.
MDL and SMD:mdl (read-only) and smd go in the 3D model category, Games field. The schema step lets .mdl and .smd learn the 3D models donut and adds an "SMD" preset to the palette after glTF.
Does that placement work for you? I'll open the first PR once you're OK with it.
Thanks, @ltsammy, the plan works for us: one settings schema step per PR (take the next free number on main when each PR lands), no donut slots, and the GMA preset in the palette only, not on the Folders donut. Go ahead with the first PR.
Activity
feat(archive): unpack Valve paks (VPK)
feat(archive): unpack the files packed into Source engine maps (BSP)
feat(archive): unpack Valve paks (VPK)
feat(archive): unpack the files packed into Source engine maps (BSP)
feat(model3d): read Source engine models (MDL) with their VTF textures
feat(archive): unpack and pack Garry's Mod addons (GMA)
feat(archive): unpack Valve paks (VPK)
feat(archive): unpack the files packed into Source engine maps (BSP)
feat(model3d): read Source engine models (MDL) with their VTF textures
feat(model3d): read and write studiomdl data (SMD), from MDL with its…
feat(model3d): read Source engine models (MDL) with their VTF textures
feat(model3d): read and write studiomdl data (SMD), from MDL with its…
feat(archive): unpack and pack Garry's Mod addons (GMA)
feat(archive): unpack Valve paks (VPK)
feat(archive): unpack the files packed into Source engine maps (BSP)
feat(model3d): read Source engine models (MDL) with their VTF textures
feat(model3d): read and write studiomdl data (SMD), from MDL with its…
feat(model3d): read Source engine models (MDL) with their VTF textures
feat(model3d): read and write studiomdl data (SMD), from MDL with its…
KnifeLemon commentedon Nov 14, 2026
Thanks, @ltsammy, and thanks again for VTF (#1483). These fit Filee well: the layouts are known from open-source tools, no new package is needed, and today each file needs its own, mostly Windows-only tool.
A few things before the PR goes up:
.., absolute paths, drive letters). Cap entry counts, entry sizes and the total unpacked size like the other archive readers do. MDL, VVD and VTX offsets and counts need bounds checks before anything is allocated._dir.vpkreads its_000.vpk… parts from the same folder. Dropping a part file on its own should give a clear message, not a broken archive.ltsammy commentedon Nov 14, 2026
Thanks! I'll split it into three PRs, one after the other, with one commit per format in each: (1) unpacking GMA, VPK and BSP, (2) packing a folder into a GMA, (3) MDL and SMD.
On your points:
ArchiveSafety.ResolveEntryPath, so.., absolute paths, drive letters and characters Windows doesn't allow never leave the output folder.ArchiveSafety.MaxEntries, and names inside the lists at 4 KB.EnsureRoombefore anything is written.CopyLimitedat its declared size, then its length and CRC are checked._dir.vpkreads its parts from its own folder. A part dropped on its own gives "… is part 003 of a Valve pak; unpack pak01_dir.vpk, which lists its files." A missing part is named in the error.Donut and schema, one schema step per PR, numbered when it's its turn. No donut slots anywhere:
gma(read-only in this PR),vpkandbspgo in the Archive category, Games field, specialist grade. The schema step only lets.gma,.vpkand.bsplearn the archives donut, as.vtflearned the images donut, with custom claims left alone. The donut's existing Extract / ZIP / 7Z slots work on them unchanged.gmabecomes writable, and a "GMA" preset goes in the palette after MRPACK, like the Minecraft and Modrinth packs. The schema step only adds that preset to existing libraries. I'd leave it off the Folders donut, because that donut is for everyone and the Games field is off in a new install. Anyone who wants it there can add it. If you'd rather have it on the Folders donut's back face, tell me.mdl(read-only) andsmdgo in the 3D model category, Games field. The schema step lets.mdland.smdlearn the 3D models donut and adds an "SMD" preset to the palette after glTF.Does that placement work for you? I'll open the first PR once you're OK with it.
KnifeLemon commentedon Nov 14, 2026
Thanks, @ltsammy, the plan works for us: one settings schema step per PR (take the next free number on main when each PR lands), no donut slots, and the GMA preset in the palette only, not on the Folders donut. Go ahead with the first PR.
feat(archive): pack a folder into a Garry's Mod addon (GMA)
feat(model3d): read Source engine models (MDL) with their VTF textures
feat(model3d): read and write studiomdl data (SMD), from MDL with its…