Perforce typemaps control how files are stored, compressed, and locked. Getting this right is critical for game development — the wrong typemap can waste terabytes of storage, corrupt binary assets, or cause merge conflicts on unmergeable files.
This guide explains every modifier we use and why.
| Modifier | What it does | When to use |
|---|---|---|
+l |
Exclusive lock (only one user can check out) | Binary assets that can't be merged: .uasset, .fbx, .psd |
+F |
Store as-is, no server compression | Pre-compressed files: .png, .jpg, .mp3, .mp4 |
+S |
Limit stored revisions (+S2 = keep 2) |
Large binaries that rarely need history: .exe, .dll |
+w |
Always writable on client | Engine-generated files: .csproj, .sln |
+x |
Set executable bit | Scripts: .sh, .bat |
+C |
Server-compressed (default for binary) | Uncompressed binary: .wav, .fbx |
Modifiers combine: binary+lF means "binary, exclusive lock, no recompression."
Binary files (textures, 3D models, maps, audio) cannot be merged. If two artists edit the same .uasset or .fbx simultaneously, one person's work is lost. The +l modifier prevents this by allowing only one checkout at a time.
Rule of thumb: If a human can't resolve a merge conflict in the file, it needs +l.
- Engine assets:
.uasset,.umap,.unity,.prefab - 3D models:
.fbx,.blend,.max,.ma,.obj - Textures:
.psd,.tga,.png,.jpg(also+F) - Audio:
.wav,.mp3,.ogg(compressed ones also+F) - Video:
.mp4,.mov,.avi
- Source code:
.cpp,.h,.cs(text, mergeable) - Config:
.ini,.json,.xml(text, mergeable) - Shaders:
.hlsl,.usf,.shader(text, mergeable) - Unity
.metafiles (YAML text, mergeable)
By default, Perforce compresses files on the server (+C). For files that are already compressed (PNG, JPG, MP3, ZIP), this wastes CPU for zero benefit — you can't meaningfully compress a PNG further.
+F tells the server to store the file as-is, skipping compression. Combined with +l:
binary+lF = exclusive lock + no recompression. Used for: .png, .jpg, .mp3, .ogg, .mp4, .zip.
binary+l (no +F) = exclusive lock + server-compressed. Used for: .wav, .fbx, .blend, .psd — uncompressed formats that benefit from server compression.
A 100MB WAV file:
binary+l→ stored as ~60MB on server (compressed)binary+lF→ stored as 100MB on server (wasted space)
A 50MB PNG file:
binary+l→ stored as ~49.5MB (CPU wasted, barely smaller)binary+lF→ stored as 50MB (correct, fast)
Executables and debug symbols are large, rebuilt constantly, and old versions are rarely needed. +S2 keeps only the 2 most recent revisions on the server, saving massive amounts of storage.
binary+S2w for executables (.exe, .dll, .dylib):
- 50MB exe, 100 builds = 5GB without
+S, 100MB with+S2 +wkeeps them writable (build tools need to overwrite)
binary+Sw for debug symbols (.pdb):
- Often 200MB+ each
+S(no number) = keep only 1 revision- Old PDB files are useless once the matching binary is gone
| File | Type | Why |
|---|---|---|
.uasset |
binary+l |
Binary, unmergeable, primary asset format |
.umap |
binary+l |
Binary level files |
.uproject |
text |
JSON, mergeable |
.uplugin |
text |
JSON, mergeable |
.ini |
text |
Config, mergeable |
.usf / .ush |
text |
Shader source, mergeable |
.csproj / .sln |
text+w |
Regenerated by engine, must be writable |
| File | Type | Why |
|---|---|---|
.unity |
binary+l |
Scene files, unmergeable in binary mode |
.prefab |
binary+l |
Prefab files, unmergeable |
.asset |
binary+l |
Serialized assets |
.meta |
text |
CRITICAL — YAML text, tracks asset GUIDs. Must be text, never binary. |
.shader |
text |
Shader source, mergeable |
.cs |
text |
C# scripts, mergeable |
.asmdef |
text |
Assembly definitions, JSON-based |
.csproj / .sln |
text+w |
Regenerated by Unity |
Unity .meta files: These small YAML files map each asset to a GUID. If a .meta file is lost or corrupted, Unity loses track of all references to that asset. They must be versioned, and they must be
texttype so Perforce can merge them properly.
The typemap files are designed to be layered:
game-dev-common.txt— Base mappings for textures, audio, 3D, video, documents, executables, scriptsunreal-engine.txtorunity.txt— Engine-specific overrides layered on top
The ENGINE environment variable controls which layers are applied:
ENGINE=unreal→ common + unrealENGINE=unity→ common + unityENGINE=common→ common onlyENGINE=none→ no typemap (manual setup)
Engine-specific entries override common entries because Perforce uses the last matching rule. So if game-dev-common.txt sets *.cs to something, and unity.txt also sets *.cs, the Unity definition wins.
All entries use //... (double slash, triple dot) which matches all depots and all paths. This means the typemap works regardless of depot name — stream depots, classic depots, whatever you create.
binary+l //.../*.uasset # Matches //game/main/Content/MyAsset.uasset
# Matches //depot/art/MyAsset.uasset
# Matches //anything/anywhere/MyAsset.uasset
If you need per-depot rules, replace //... with //depotname/....
# View current typemap
p4 typemap -o
# Edit typemap interactively
p4 typemap
# Apply from file
p4 typemap -i < typemap.txt