Futile separates an image registry from the nodes drawn by a camera. An atlas owns a texture and named elements within it. An FSprite selects one element. An FContainer holds the sprite in a draw hierarchy. A shader controls how Futile renders the node.

The game initializes Futile and its atlas manager. Mod code should use Futile.atlasManager after that initialization, rather than calling Futile.Init(FutileParams) again. During initialization, Futile.CreateDefaultAtlases() creates a white texture and registers it as Futile_White.

Atlas and element names are registry keys

FAtlasManager.LoadAtlas(System.String) first checks whether an atlas with that path key is already registered. If it is, the method returns that atlas. Otherwise it passes the supplied path and paths built with the current Futile.resourceSuffix into the lower loading method.

FAtlasManager.LoadImage(System.String) also reuses an existing atlas by name. For a new entry, it passes an empty data path. The lower method treats that empty data path as a single image rather than an atlas with separate element data.

These methods show how the registry distinguishes the two loading requests. They do not establish a public mod asset directory convention. Futile.resourceSuffix is mutable runtime state, and this verification did not test paths through Rain World’s mod asset resolver. Confirm the path, suffix, case behavior, packaging, and reload behavior in a running mod before relying on a loading path.

When an atlas is added, FAtlasManager.AddAtlas(FAtlas) records each element by name. A duplicate element name throws a FutileException. Use a prefix unique to the mod so another atlas is unlikely to claim the same key.

Before constructing a sprite, code can check the exact intended element:

if (!Futile.atlasManager.DoesContainElementWithName(elementName))
    return;
 
FSprite sprite = new FSprite(elementName);

FSprite..ctor(System.String,System.Boolean) resolves its element through Futile.atlasManager.GetElementWithName. That lookup returns an exact match when one exists. If it does not find one, it performs a fallback search using the final part of the supplied path. The fallback may make an ambiguous name appear to work, so an explicit key and DoesContainElementWithName check give the mod a clearer failure path.

Drawable lifetime covers where the resulting sprite array belongs. Camera coordinates covers placement in a room camera container.

Existing shaders and new wrappers

Rain World keeps named FShader entries in game.rainWorld.Shaders. The verified room camera assigns an existing entry with an expression of this form:

sprite.shader = game.rainWorld.Shaders[shaderName];

The index operation requires the selected key to exist. Check the exact name at runtime and disable the visual feature or use a tested fallback when it is missing. Source inspection did not verify a general list of stable shader names or the appearance of any shader on a custom sprite.

FShader.CreateShader(System.String,UnityEngine.Shader) covers a different case. It accepts a short registry name and a Unity Shader. If the short name already exists, it returns the registered FShader. For a new name, it constructs and registers a wrapper. Its constructor throws when the supplied Unity shader is null.

Choose a unique short name and validate the Unity shader before creation. Reusing a short name does not replace the existing wrapper, so a collision can silently select another registration rather than the shader the caller supplied.

Shader assignment and atlas loading solve separate problems. A valid atlas element can render with an unsuitable shader. A valid shader cannot supply a missing sprite element. Diagnose the registry entry and shader lookup independently.

Unloading affects shared state

FAtlasManager.ActuallyUnloadAtlasOrImage(System.String) removes the atlas’s element names from the shared registry, unloads the atlas, destroys its texture when the atlas is not an asset, and removes the atlas entry. Existing sprites or other mods may still refer to those elements or that texture.

Static inspection supports the fact that unloading changes shared registry state. It does not supply a safe universal point for a plugin to unload an atlas. Before unloading, establish ownership of the atlas name and every element key, then test disable and re-enable behavior, live sprites, room changes, and other enabled mods.

No game session was launched for this article. Asset placement, element discovery, name collisions during a mod load, shader keys, rendered appearance, texture lifetime, and compatibility with custom renderers remain runtime checks.

Sources

  • Rain World v1.11.8, Steam app 312520, build 22785462. Assembly-CSharp.dll SHA-256 B6BE1D4E18CE219D21091B51564CB6A11C1E4106B41DE903EB8E58849CB16FDB.
  • Assembly-CSharp.dll: Futile.Init(FutileParams) and Futile.CreateDefaultAtlases().
  • Assembly-CSharp.dll: FAtlasManager.LoadAtlas(System.String), FAtlasManager.LoadImage(System.String), FAtlasManager.ActuallyLoadAtlasOrImage(System.String,System.String,System.String), and Futile.resourceSuffix.
  • Assembly-CSharp.dll: FAtlasManager.AddAtlas(FAtlas), FAtlasManager.DoesContainElementWithName(System.String), and FAtlasManager.GetElementWithName(System.String).
  • Assembly-CSharp.dll: FAtlasManager.ActuallyUnloadAtlasOrImage(System.String).
  • Assembly-CSharp.dll: FShader.shader, FShader.CreateShader(System.String,UnityEngine.Shader), and the global::RoomCamera constructor.
  • Runtime reference records the same installed assembly baseline and its verification limits.