SprayPaint
Spray colored marks, PNG/JPG images and animated GIFs on GTFO surfaces. Includes presets, a color palette, galleries and optional multiplayer image sharing.
By issy
| Date uploaded | a day ago |
| Version | 0.1.7 |
| Download link | issy-SprayPaint-0.1.7.zip |
| Downloads | 9 |
| Dependency string | issy-SprayPaint-0.1.7 |
This mod requires the following mods to function
BepInEx-BepInExPack_GTFO
BepInEx pack for GTFO. Preconfigured and includes Unity Base DLLs.
Preferred version: 3.2.3README
SprayPaint
SprayPaint lets you place colored marks, PNG/JPG images and animated GIFs on GTFO surfaces. It includes a keyboard-driven menu, presets, a color palette, local and received galleries, and optional multiplayer image sharing.
The menu and all settings work while playing; they do not require restarting the game.
Image Folders
Images are read from the Sprays folder next to the installed DLL:
BepInEx\plugins\<namespace>-SprayPaint\SprayPaint\Sprays\
BepInEx\plugins\<namespace>-SprayPaint\SprayPaint\Sprays\Received\
If the game logs a different path, use the logged one. Look for:
[SprayPaint] sprays folder: ...
PNG, JPG and GIF are supported. WebP is not supported by GTFO's Unity version.
The actual image type is detected from the file header, not only the extension. A GIF renamed to .jpg still loads as an animation.
On upgrade, images from the old global folder are migrated automatically:
BepInEx\plugins\SprayPaint\Sprays
Installation
Thunderstore / R2ModMan
Install with the mod manager. BepInEx is declared as a dependency.
Manual
Copy this package's BepInEx folder into the game folder, then start the game once.
Controls
The menu is keyboard-only.
| Key | Action |
|---|---|
F7 |
Open menu |
ESC |
Go back / close menu |
Up / Down |
Select tab or row |
Left / Right |
Change category / adjust value |
Y |
Activate row / rebind action key |
Shift+Y |
Save preset in preset grid |
Backspace |
Clear preset (press twice) |
R |
Switch main / received gallery |
H |
Spray |
F10 |
Clear all local and multiplayer images |
F8 |
Clear local images only |
F9 |
Clear multiplayer images only |
B |
Toggle multiplayer master switch |
F11 |
Undo last decal |
Action keys can be changed in:
Actions -> select the key row -> Y -> press a new key
Multiplayer
Multiplayer is off by default. Press B to toggle it, or set it in the config:
[Network]
MultiplayerEnabled = false
Enabled = false
AutoDownload = false
ServeFiles = false
For normal co-op:
[Network]
MultiplayerEnabled = true
Enabled = true
AutoDownload = true
ServeFiles = true
What each setting does:
MultiplayerEnabled- master switch. Off: stop receiving, sending, downloading and displaying new remote sprays. Existing remote decals stay visible.Enabled- broadcast your own sprays to other players.AutoDownload- automatically request images from the sender.ServeFiles- allow other players to download images from you.UploadLimitKB- outgoing transfer limit in KB/s.0= unlimited. Options: 128 / 256 / 512 / 1024 / 2048 / unlimited.PerPlayerUpload- when on, each receiving player gets a separate upload limit instead of sharing one limit.RemoteSizeMeters- received spray size in meters.0follows the sender's size.MaxVisibleRemoteGifs- maximum number of remote GIFs that animate at once. Extra GIFs stay visible but their animation pauses.AtlasMode- baked GIF atlas transfer:0off,1automatic after the source finishes downloading and local baking is still not ready after 30 seconds,2always request the baked atlas.HiddenRemotePlayers- comma-separated Steam IDs of teammates whose sprays are hidden.
All players should use the same SprayPaint version when playing together.
Multiplayer transferred data:
- spray position, normal, color, size, shape and image name
- source images by request
- optional baked
.gifatlassnapshots
Transfer uses GTFO's reliable GameOrderCritical channel, verifies SHA-256, and resends missing chunks with ACK bitmaps.
GIF And BC7
GIFs are baked into BC7F atlases on the local machine.
- Multi-page atlases are supported.
- Long GIFs are sampled evenly so the full animation duration is preserved instead of truncating the first N frames.
GifMinFrameDelayMs(default 50) prevents GIFs with zero frame delay from playing at 50 FPS.GifMaxFramescontrols the number of baked frames. Lower values reduce memory and disk use.AtlasMaxSizecontrols the maximum size of each baked GIF frame.- GIFs with content renamed to
.png/.jpgare detected by file header.
Changing GIF frame settings requires the old atlas to be regenerated. Delete the corresponding .gifatlas file and restart, or change the setting from the menu.
Cache Index
The mod keeps an index of generated caches:
Sprays\.cache\index.tsv
It is used to remove GIF/static/BC7 caches when their source image is deleted.
- Duplicate index entries are rejected and cleaned up automatically.
- Orphan
.texturecachefiles are removed when their source image no longer exists. - Deleting
Sprays\.cache\index.tsvis safe; it is rebuilt on demand. - Do not manually edit cache files while the game is running.
Presets And Colors
The preset page has 12 slots:
Shift+Y save preset
Y apply preset
Backspace clear preset (press twice)
The color palette supports favorites and recent colors.
The language can be changed in:
Image -> Language
Supported menu languages: English, Chinese, Korean.
Known Limitations
- Sprays do not fully conform to curved surfaces; they are flat quads.
- Very large images, many visible sprays or double-sided rendering can reduce FPS.
- WebP is unsupported; convert to PNG/JPG first.
- The menu does not support mouse input.
- Changing GIF frame settings does not invalidate old atlases automatically; delete them or rebake from the menu.
- Existing remote decals are not restored after turning multiplayer off and on; only new sprays appear.
- All players should use the same mod version for multiplayer compatibility.
中文说明
SprayPaint 可以在 GTFO 的墙面、地面和物体上喷涂纯色标记、PNG/JPG 图片和 GIF 动画。
图片目录
图片放在 DLL 旁边的 Sprays 目录:
BepInEx\plugins\<namespace>-SprayPaint\SprayPaint\Sprays\
BepInEx\plugins\<namespace>-SprayPaint\SprayPaint\Sprays\Received\
实际路径以日志为准:
[SprayPaint] sprays folder: ...
支持 PNG、JPG、GIF。WebP 不支持。
旧版本全局目录中的图片会自动迁移。
安装
Thunderstore / R2 直接安装;手动安装时把包内 BepInEx 文件夹复制到游戏目录。
按键
F7 打开菜单
ESC 返回 / 关闭菜单
方向键 选择 / 切换 / 修改
Y 执行 / 改键
Shift+Y 保存预设
Backspace 清除预设(按两次确认)
R 主图库 / 接收图库
H 喷漆
F10 清空本地和联机全部图片
F8 只清空本地图片
F9 只清空联机图片
F11 撤销
B 联机功能开关
动作分类中可以给清空、联机等快捷键改键。
联机
联机默认关闭。
[Network]
MultiplayerEnabled = false
Enabled = false
AutoDownload = false
ServeFiles = false
正常联机:
[Network]
MultiplayerEnabled = true
Enabled = true
AutoDownload = true
ServeFiles = true
说明:
MultiplayerEnabled 联机功能总开关
Enabled 是否广播自己的喷漆
AutoDownload 是否自动下载别人的图片
ServeFiles 是否允许别人从自己这里下载图片
UploadLimitKB 上传限速,0 = 不限速
PerPlayerUpload 每人独立限速
RemoteSizeMeters 远程图片大小,0 = 跟随对方
MaxVisibleRemoteGifs 远程 GIF 同时播放动画数量
AtlasMode 成品图集传输:0关 / 1自动30秒 / 2总是
HiddenRemotePlayers 隐藏指定队友的 Steam ID
关闭联机功能后:
不再接收/发送/下载新图片
已有远程贴花保留
GIF
GIF 会在本地烘焙成 BC7F 图集。
- 支持多页图集
- 长 GIF 均匀抽帧,保留完整时长
GifMinFrameDelayMs防止 0 延迟 GIF 过快GifMaxFrames控制烘焙帧数AtlasMaxSize控制单帧最大尺寸
修改这些设置后需要重新生成 .gifatlas。
缓存
Sprays\.cache\index.tsv
用于记录图片对应的缓存文件。
- 重复索引会自动去重
- 图片删除后
.texturecache孤儿缓存会自动清理 - 删除
index.tsv是安全的,会自动重建
已知限制
- 喷漆是平面四边形,不能完全贴合曲面
- 大量图片或双面渲染会降低 FPS
- 不支持 WebP
- 菜单不支持鼠标
- 联机双方需要相同版本
CHANGELOG
Changelog
0.1.8
- Fixed overlapping decal flicker:
- Back face offset 3 mm.
- Overlap depth stagger 1.5 mm per layer, capped at 30 mm.
0.1.4
- Added a multiplayer master switch (
Bby default), action hotkey rebinding, per-player upload limits, remote GIF animation limits, remote spray size in meters, baked GIF atlas transfer and hidden teammate sprays. - The multiplayer master switch defaults to OFF, so a fresh install starts fully offline; press
Bto enable it. - ESC now returns/closes every menu level.
- Cache index now removes duplicate
index.tsventries instead of appending the same source/cache pair repeatedly. - Fixed orphan
.texturecachefiles not being removed after their source image was deleted. Orphan texture/BC7 caches are now detected by rebuilding the expected cache path set from the currentSpraysandReceivedimages. - BC7 cache writes are now registered in the cache index on both sync and async paths.
- Long GIFs are sampled evenly to preserve their full duration instead of truncating.
- Added a minimum GIF frame delay to stop zero-delay GIFs from playing at 50 FPS.
- Removed the old experimental Steam P2P, compression, host-policy, missing-list and remote cap logic from the transfer layer.
Retained transfer core (not new)
-
Source-image transfer, SHA-256 validation and missing-chunk ACK resend were kept from the old transfer layer. They are listed here as retained behavior, not as new 0.1.4 features.
-
PNG/JPG now use the managed StbImageSharp decoder on a background thread, then upload raw RGBA on the main thread. This is true background decode instead of main-thread
Texture2D.LoadImage. StbImageSharp is licensed under Unlicense OR MIT. -
GIF gallery previews are now asynchronous; the first frame appears after background decode/upload instead of blocking the menu.
-
Removed the in-game image deletion key; delete image files in Explorer instead. Missing-image caches are cleaned automatically on startup and gallery refresh.
-
GIF spray startup no longer decodes a preview synchronously; pending GIFs use a placeholder and fill in asynchronously. GIF file reads also happen off the main thread.
-
Fixed JPG/PNG not appearing after the async change on GTFO's IL2CPP build:
UnityWebRequestTexturerequires a missingDownloadHandlerTexture(bool)constructor. Fallback now uses async file download + main-threadLoadImage. -
Gallery refresh now cleans index entries for images deleted outside the menu.
-
PNG/JPG static material and preview loading is asynchronous; the image cache index also covers static/DXT/send caches.
-
PNG/JPG material and preview decoding is now asynchronous (UnityWebRequestTexture), so the main thread no longer performs image decode on first use.
-
Added a cache index (
Sprays/.cache/index.tsv). Deleting an image from the gallery deletes its GIF/static/DXT/send caches; missing images are cleaned on startup. Legacy unindexed caches are purged once. -
Network transfer compression now detects GIF/PNG/JPEG by file header, not just extension.
-
GIF frame dedupe now uses a 64-bit hash instead of a byte-by-byte compare.
-
GIF decode dimension limit raised to 4096; added
GifMaxFrames(default 120) to bound frame memory. -
Added a bounded in-memory GIF cache with LRU eviction; active sprays/materials are never evicted. New options:
GifMemoryCacheMB(default 256) andGifMemoryCacheCount(default 8). -
GIF animation now pauses while its renderer is off-screen (
GifPauseOffscreen, default true). -
GIF decoder now merges identical consecutive frames and extends the previous frame's delay, reducing texture count and memory use.
-
Image format detection now uses file headers instead of relying only on the extension. GIF content stored under a
.png/.jpgname is decoded as GIF; WebP content is reported as unsupported instead of silently failing. -
Horizontal flip is now applied consistently to PNG, JPG and GIF textures.
FlipStaticImageskeeps its config key but affects all image formats. -
Unsupported WebP images now log a clear warning.
-
Menu/README format notes updated.
0.1.3
- Data folders are now created next to
SprayPaint.dll, so Thunderstore/R2ModMan installs showSpraysunder the installed plugin folder instead of the global plugin root. - Old images in the global
BepInEx/plugins/SprayPaint/Spraysfolder are migrated automatically. - Images placed directly beside the DLL are migrated into the new
Spraysfolder. - Documentation updated with the new paths.
0.1.2
- Documentation only: clarify the
SpraysandSprays/Receivedfolders and move the image-folder instructions to the top of the README. - No gameplay changes.
0.1.1
- Added host-controlled multiplayer file transfer permission.
- Added independent received-image dimension limit.
- Added received spray size override.
- Received images are now stored only in
Sprays/Received. - Added menu X/Y position rows with screen clamping.
- Added preset delete confirmation with Backspace.
- Fixed ARGB/RGBA texture cache channel swap that caused reddish or oversaturated images.
- Fixed cache-hit logging when the target file already exists.
- Updated Thunderstore README and package metadata.
0.1.0
- Initial release.
- Color, image and animated GIF sprays.
- Presets, color palette, favorites and recent colors.
- Separate local and received image galleries.
- Optional multiplayer synchronization with chunked file transfer.
- Targeted requests, fallback broadcast, ACK-based resend and SHA-256 validation.
- Content hash cache and persistent hash index.
- Host-controlled file transfer permission.
- Receiver image size and pixel limits.
- Menu position adjustment with screen clamping.
- Keyboard-only menu operation.