You are viewing a potentially older version of this package. View all versions.
issy-SprayPaint-0.1.7 icon

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-3.2.3 icon
BepInEx-BepInExPack_GTFO

BepInEx pack for GTFO. Preconfigured and includes Unity Base DLLs.

Preferred version: 3.2.3

README

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. 0 follows 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: 0 off, 1 automatic after the source finishes downloading and local baking is still not ready after 30 seconds, 2 always 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 .gifatlas snapshots

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.
  • GifMaxFrames controls the number of baked frames. Lower values reduce memory and disk use.
  • AtlasMaxSize controls the maximum size of each baked GIF frame.
  • GIFs with content renamed to .png/.jpg are 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 .texturecache files are removed when their source image no longer exists.
  • Deleting Sprays\.cache\index.tsv is 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 (B by 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 B to enable it.
  • ESC now returns/closes every menu level.
  • Cache index now removes duplicate index.tsv entries instead of appending the same source/cache pair repeatedly.
  • Fixed orphan .texturecache files 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 current Sprays and Received images.
  • 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: UnityWebRequestTexture requires a missing DownloadHandlerTexture(bool) constructor. Fallback now uses async file download + main-thread LoadImage.

  • 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) and GifMemoryCacheCount (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/.jpg name 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. FlipStaticImages keeps 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 show Sprays under the installed plugin folder instead of the global plugin root.
  • Old images in the global BepInEx/plugins/SprayPaint/Sprays folder are migrated automatically.
  • Images placed directly beside the DLL are migrated into the new Sprays folder.
  • Documentation updated with the new paths.

0.1.2

  • Documentation only: clarify the Sprays and Sprays/Received folders 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.