Skins
Modular skin support (no more replacing asset files!)
| Date uploaded | a month ago |
| Version | 0.12.0 |
| Download link | food-Skins-0.12.0.zip |
| Downloads | 667 |
| Dependency string | food-Skins-0.12.0 |
This mod requires the following mods to function
AuriRex-Clonesoft_Json
Library - Newtonsoft.Json but in a renamed namespace.
Preferred version: 13.0.0BepInEx-BepInExPack_GTFO
BepInEx pack for GTFO. Preconfigured and includes Unity Base DLLs.
Preferred version: 3.2.2README
Skins
Modular Skin Support for GTFO
English Documentation | 中文文档 | Repository | Latest SkinGroup Editor Build
For feedback and issues, DM @uwufood OR the feedback thread on the GTFO Modding Discord Server
How to Use
- This mod is a library mod, which means it DOES NOT come with any skins by default. You can look at the dependants
of this mod, these are likely skin packs you can download.
- For alternative ways of installing/obtaining skins, please refer to the documentation.
- For creating skins packs (skin groups), refer to the documentation.
Documentation
- Everything you need to know about to use this mod to its full extent is included in the documentation.
- When in doubt, refer to the documentation. If you have any questions or suggestions, please don't hesitate to reach out to me on Discord.
Hot Reload
- Skins can be hot reloaded and take effect mid-game.
- Refer to the Reloading Skins section of the documentation for details.
- NOTE: The current version of the plugin might differ from the documentation slightly.
FAQ
- Q: Do I have to reinstall skins for each modded profile?
- Short Answer: No
- Long Answer: When a skin is installed as a mod (i.e. from Thunderstore, local mod, in mod managers), it is installed
under the per profile skins folder (
<BepInEx>/Assets/Skins/). When the mod is first launched, it attempts to move all per profile skins to the global skins folder which is shared across all profiles. If there are no complications, you should only have to install skins once and they will be available for all profiles. The process is described here. If there are any issues, please shoot me a message on Discord.
Attribution / Dependencies
Plugin
Libraries shipped next to Skins.dll (pure C# ports of nothings/stb by StbSharp, MIT):
StbImageSharp- Decodes skin PNG/JPG textures on worker threads.
StbDxtSharp- DXT1/DXT5 compression, so skin textures take roughly a quarter of the VRAM of an uncompressed upload.
SkinGroup Editor
- Electron / electron-vite, React, zustand
- The app itself.
AssetsTools.NETandAssetsTools.NET.Texture(MIT), withAssetRipper.TextureDecoder- Reading GTFO asset files and building asset bundles for the Port feature (for the bundled wrapper/util
ExtractorCore).
- Reading GTFO asset files and building asset bundles for the Port feature (for the bundled wrapper/util
StbImageWriteSharp(MIT)- Writes extracted textures out as PNG.
classdata.tpk: Built by AssetRipper/Tpk (MIT) from AssetRipper/TypeTreeDumps and shipped unmodified.- The Unity type-tree database that lets the above read release builds.
CHANGELOG
v0.12.0
TL;DR: Gear icons now show your skins. The skin selection popup previews every skin on the actual weapon, and the lobby/inventory icons update when you pick one.
- feat: per-skin preview icons in the skin selection popup. Each entry shows the weapon wearing that skin; the active skin is pre-selected with its preview shown on the right when the popup opens. Icons are cached on disk and only re-rendered when a skin's files change.
- feat: the game's own gear icons (lobby bar, inventory) show the equipped skin and refresh immediately after selecting a skin, including after a skins reload.
- feat: new
Skin Icon Styleconfig option (Loading section):Lit(default) = icons rendered with the weapon's real materials under lobby lighting, emissive included. Closest to how the weapon looks in game.Vanilla= icons rendered with the game's own icon shading, skinned. Matches the stock look.Off= icons left untouched (unskinned) and no popup previews. Fastest boot: the game's icon pass no longer loads any skin textures.
- fix: entering the lobby no longer freezes while skin textures for the game's icon pass are still loading; icons that rendered before their textures arrived are re-rendered once loading settles.
- fix: selecting the already active skin again no longer re-applies it.
Dev Notes
The game renders icons through its deferred GBuffer with a cubemap-lit shading pass and no emissive, which is why skinned icons used to look off.
Lit renders the posed model ourselves with the forward lobby-lighting variant of the gear shader, framed the way the game frames icons. Weapon parts on shaders without a forward pass (the vanilla pistol bodies) keep the game's render. --LogIconJobs dev opt logs icon job settings and timings.
v0.11.1
- fix: shell pool not updating on skins reload -- becomes empty texture.
v0.11.0
TL;DR: This version introduces significant performance improvements, especially for large skin libraries. Startup time is drastically reduced, and VRAM usage is now dependent on the skins in use rather than the total amount of installed skins.
- feat: lazy skin loading. Textures and meshes are loaded when a gear item that uses them spawns
and freed once nothing references them, instead of everything from every installed skin group
at startup.
- New
Loadingconfig section:- Skin Load Mode
Eager= old behaviorCompatible= default, also keeps every skin group compatible with each equipped item resident so swapping is instantActive= only what the active skin uses; a swap loads in the background) and
- Skin Unload Mode
ImmediateorIdleafterUnload Idle Seconds, default 60
- Skin Load Mode
- effects: Startup on a 21-group / 448-texture install went from ~82 s to ~0.2 s; VRAM is bounded by the skins in use instead of the skins installed, which means a significantly reduced memory footprint depending on your skin library size.
- New
- feat: textures are now DXT-compressed on load (DXT1 without alpha, DXT5 with). Reduces memory footprint per texture.
--NoCompressdev opt disables it. - feat: texture decoding, mipmap generation, and compression run in managed code on worker threads; the main thread only uploads.
- Now ships
StbImageSharp.dllandStbDxtSharp.dllnext toSkins.dll. --LegacyLoaddev opt restores Unity's ownLoadImage/Compresspath.
- Now ships
- feat: per-skin-group load timing and a load summary in the log.
- feat: updated skin reload dialog display
- fix: a renderer's material is only instanced once a skin is actually applied to it, so renderers no skin touches keep sharing the game's material.
- fix: shell-pool setup leaked vanilla-texture retains on every re-skin.
- fix:
Texture2DProperty.Unload()used the manifest-relative path as its cache key, so it never matched the entryLoad()had created.
Dev Notes
The per-texture cost that made startup slow was Unity's LoadImage (PNG decode) and Compress
(DXT), both main-thread only -- moving file I/O off-thread alone would not have helped.
The new pipeline decodes and compresses entirely in managed code on workers and hands the main thread a
finished blob for LoadRawTextureData (~3 ms per texture), which is also what makes in-game skin
swaps fast.
Ownership is an owner set per texture/bundle rather than a counter, so a target re-running its update can't double-count, and releases are deferred to a periodic sweep so a release-then-reacquire within one frame (every swap) never touches disk.
v0.10.0
- feat: Skins menu page instead of more buttons
- feat: moved some settings to settings menu page, thus global instead of per-profile.
v0.9.3
- fix:
WeaponShellManager.OnLevelCleanupwould throw because we usenullas pool placeholder.- This causes faulty level cleanup if called by some mods, and would cause all subsequent level generations to fail until the game is restarted.
- We now always fill the pool with a valid empty
GameObjectPoolto prevent this issue.
- feat: add option to turn on mipmap generation for skin textures.
- feat: add
HarmonyWrapSafeto all patches to prevent patch failures from breaking the game. - refactor: initialize skins on level gen
Builder.OnFactoryDoneinstead.
v0.9.1
- fix: in some setups, gear might be missed in target setup
- Now we setup all inventory gear on level start, so local player gear is guaranteed to be a target and setup.
v0.9.0
- fix: casing is not recorded if it is not part of the gun model
- fix: hacking Tool etc. can now be targeted because we attach at Item level
- feat: ManagedGroupTarget that attaches to any Item
- Things like Hacking Tool can now be targeted
- feat: mags are now skinned
- refactor: we don't assume
MeshRenderersall haveMeshFilterwith it. - refactor: change
inttypes for persistentID touint.
v0.8.1 / v0.9.2
- v0.9.2 (rollback-hotfix) points to this version
- fix: possible security issues
v0.8.0
- feat: support for installing
skinspkginternal format packages. - feat: change 'Update All Material Targets' button to 'Open Global Skins Folder' button
v0.7.0
- feat: mesh replacement via Mesh Targets
- refactor: adjust schema to use
match_groupsinstead ofmatchGroupsfor consistency.
v0.6.3
- fix: premature texture unload by Unity due to no references
- feat: manage destruction of Vanilla textures with ref count and
HideFlags.DontUnloadUnusedAsset.
Dev Notes
There has been an issue where skins would sometimes stop applying correctly. Reverting to Vanilla skins after dropping in
and out of level would also result in Vanilla textures being destroyed by Unity's resource management. This is because Skins'
management of textures are not considered as part of Unity's reference counting system. This update fixes this issue by
managing the lifecycle of textures with a ref count and HideFlags.DontUnloadUnusedAsset to prevent Unity from unloading
them prematurely.
v0.6.1 / v0.6.2
- fix: gear ID extraction can cause NRE if item has no
PlayfabInstanceId - feat: added an "Update All Material Targets" button to settings
v0.6.0
- fix: incorrect callsite for OnSetActive for selection item
- fix: skin button disappearing when using LegacyLobby
- fix: make OnAllPartsSpawned to be patched at lowest priority (might be related to skins not applying in some modded rundowns)
- feat: skin reload indication and progress display
- feat: French localization (thank you @Ocha!)
- feat: Traditional Chinese localization
- chore: suppress GTFO localization not ready warnings
- docs: update README
v0.5.3
- fix: material keyword restore on revert:
DisableKeyword("*")was a no-op; now iteratesshaderKeywordscorrectly - fix:
_cleanflag being set after the property loop; it is now set before so a partial-apply failure can't leave the target in an inconsistent state - fix: when a configured skin GUID is no longer found in the registry, the target now auto-reverts to vanilla and clears the stale entry
- feat: auto-move from per-profile to global now replaces the existing global copy on collision rather than skipping, so per-profile is always treated as the up-to-date source
v0.5.2
- docs: update README with Hot Reload information
v0.5.1
- feat: initial Release