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 | 6 days ago |
| Version | 0.1.3 |
| Download link | issy-SprayPaint-0.1.3.zip |
| Downloads | 28 |
| Dependency string | issy-SprayPaint-0.1.3 |
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, separate local and received galleries, and optional multiplayer image sharing.
Image Folders (Important)
Your own images
Put your images in the Sprays folder next to SprayPaint.dll:
Manual install: BepInEx/plugins/SprayPaint/Sprays/
Thunderstore / R2: BepInEx/plugins/<namespace>-SprayPaint/SprayPaint/Sprays/
The exact path is also written to BepInEx/LogOutput.log as:
[SprayPaint] sprays folder: ...
Then press F7 in game and open the Image category.
Supported formats:
.png
.jpg
.jpeg
.gif
These images appear in the main gallery.
Received images
Images downloaded from other players are stored automatically in the Received folder inside that same Sprays directory:
...\Sprays\Received\
Do not put your own images in Received; they will only appear in the received gallery. To keep an image in your own main gallery, put it in Sprays instead.
The Received folder is created automatically. You do not need to create it manually. Files in Received can be deleted to free space.
If you update from an older version, images are migrated automatically from the old global BepInEx/plugins/SprayPaint/Sprays location.
中文说明
自己的图片:
放到 SprayPaint.dll 同级的 Sprays 文件夹
手动安装:BepInEx/plugins/SprayPaint/Sprays/
Thunderstore/R2:BepInEx/plugins/<命名空间>-SprayPaint/SprayPaint/Sprays/
按 F7 → 图片分类选择
队友发来的图片:
自动保存到同一个 Sprays 下的 Received/
只显示在“接收图库”,不会出现在主图库
自己的图片不要放进 Received。
Received 文件夹会自动创建,不需要手动新建。
旧版本图片会自动迁移。
Multiplayer is disabled by default.
To use multiplayer, enable
Network.Enabled,Network.AutoDownloadandNetwork.ServeFilesinBepInEx/config/SprayPaint.cfg. All players should use the same SprayPaint version.
Features
Press
F7in game to open the SprayPaint menu and change settings without leaving the game.
- Solid color sprays
- PNG and JPG image sprays
- Animated GIF sprays
- Adjustable size, shape, opacity and lifetime
- Ground single-sided rendering
- Distance scaling and distance culling
- Spray sound
- Object pool, texture cache, LRU and mipmaps
- English, Chinese and Korean menu languages
- 4×3 preset grid (6 color presets + 6 full presets)
- Color palette with favorites and recent colors
- Separate main and received image galleries
- Adjustable menu position with screen clamping
- Multiplayer position/color/size/shape synchronization
- Chunked image transfer with targeted requests and fallback broadcast
- ACK-based missing chunk resend and SHA-256 validation
- Content hash cache and persistent hash index
- Host-controlled file transfer permission
- Receiver image size and pixel limits
- Received spray size override
Controls
The menu is keyboard-only.
| Key | Action |
|---|---|
F7 |
Open / close the menu |
Up |
Go to the tab bar |
Left / Right |
Change category / adjust the selected value |
Down |
Enter the list / go back |
Up / Down |
Select a menu row |
Y |
Activate the selected row |
Shift+Y |
Save a preset in the preset grid |
Backspace |
Clear a preset (press twice to confirm) |
R |
Switch between the main and received galleries |
Esc |
Go back |
Installation
Thunderstore
Install with the mod manager. The BepInEx package is declared as a dependency.
Manual
- Install BepInEx 6 (IL2CPP) for GTFO.
- Copy
BepInEx/plugins/SprayPaint/SprayPaint.dllinto your GTFO folder. - Start the game once.
The plugin creates the data folders next to SprayPaint.dll:
<plugin folder>/Sprays/
<plugin folder>/Sprays/Received/
BepInEx/config/SprayPaint.cfg
For Thunderstore/R2ModMan, <plugin folder> is normally:
BepInEx/plugins/<namespace>-SprayPaint/SprayPaint/
The exact path is logged as sprays folder: ....
Multiplayer Setup
Open BepInEx/config/SprayPaint.cfg and enable:
[Network]
Enabled = true
AutoDownload = true
ServeFiles = true
Important settings:
[Network]
HostAllowTransfer = true
MaxDownloadMB = 12
MaxReceiveImageDimension = 4096
RemoteSpraySize = 0
Enabledbroadcasts local sprays to other players.AutoDownloadrequests missing images automatically.ServeFilesallows the game to serve images to other players.HostAllowTransferis controlled by the host. If the host disables it, the whole lobby stops transferring and downloading files.MaxDownloadMBlimits the file size of every received or sent image. It is not GIF-only.MaxReceiveImageDimensionrejects received images whose decoded width or height is too large.RemoteSpraySize = 0follows the sender's size. Set a value between0.1and5to force a local display size.
All players should use the same SprayPaint version when playing together.
Configuration
The menu exposes the most commonly used settings. Advanced settings are available in SprayPaint.cfg.
Useful defaults:
[Paint]
Size = 0.33
Offset = 0.02
MaxDecals = 50
MaxTextureSize = 2048
ImageBrightness = 0.35
ImageGamma = 1
Opacity = 1
DoubleSided = true
GroundSingleSided = true
DistanceScale = true
Files
Own images Sprays/
Received images Sprays/Received/
Texture cache Sprays/.texturecache/
Hash index Sprays/.cache/hashindex.tsv
Config BepInEx/config/SprayPaint.cfg
Local images appear in the main gallery. Images received from other players appear in the received gallery.
Known Limitations
- Sprays do not fully conform to curved surfaces.
- Large images, many active sprays, or double-sided rendering can reduce FPS.
- There are no projected decals; sprays are flat quads.
- Compressed transfers can change file bytes, but the result is validated as a decodable image.
- Enabling GIF compression sends only the first frame, making the spray static.
- The menu does not support mouse control.
- When the host disables file transfer, no player in the lobby can transfer or download files.
中文说明
SprayPaint 是一个 GTFO 喷漆 Mod,可以在墙面、地面和物体上喷涂纯色、PNG/JPG 图片或 GIF 动画,并支持多人联机共享。
默认关闭联机
安装后联机默认关闭。要使用联机,请在 BepInEx/config/SprayPaint.cfg 中打开:
[Network]
Enabled = true
AutoDownload = true
ServeFiles = true
所有联机玩家需要使用相同版本的 SprayPaint。
键盘操作
F7 打开/关闭菜单
方向键 选择 / 切换 / 修改
Y 执行
Shift+Y 保存预设
Backspace 删除预设(按两次确认)
R 主图库 / 接收图库
Esc 返回
菜单不支持鼠标操作。
打开菜单
在游戏内按 F7 即可打开菜单并修改设置。
房主权限
房主可以在联机菜单中关闭文件传输。关闭后,整个房间停止传输和下载,其他玩家的本地开关不会生效。
Credits
Icon character and background artwork are provided by the mod author. Character rights belong to their original owners.
Changelog
See CHANGELOG.md.
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.