Rain World advances a global::MainLoopProcess through fixed simulation updates and one graphics update per raw update. The process’s framesPerSecond defaults to 40, but global::RainWorldGame.RawUpdate(float) changes it for game state. Forty updates per second is a default, not a constant tick rate for every situation.

flowchart TD
    A[ProcessManager.Update] --> B[RawUpdate]
    B --> C[Simulation updates]
    C --> D[GrafUpdate]

MainLoopProcess.RawUpdate(float) adds dt * framesPerSecond to an accumulator. While enough accumulated work remains, it calls Update() and consumes one unit. One raw call can therefore run zero, one, or several simulation updates. After the simulation work, it calls GrafUpdate(myTimeStacker) once. timeStacker is an interpolation amount. It is not elapsed seconds.

This loop is separate from the Unity callback cadence that reaches ProcessManager.Update(float). A mod’s Unity Update() callback does not prove that one Rain World simulation tick occurred. Count work in the Rain World method whose lifetime matches the feature.

Update state, then interpolate drawing

For a visual that follows simulation state, record previous and current values during the object’s update and interpolate them during drawing:

lastMarkerPos = markerPos;
markerPos = observedPosition;
Vector2 worldPos = Vector2.Lerp(lastMarkerPos, markerPos, timeStacker);
Vector2 screenPos = worldPos - camPos;
sLeaser.sprites[0].x = screenPos.x;
sLeaser.sprites[0].y = screenPos.y;

The first fragment belongs in a verified game update path. The second belongs in IDrawable.DrawSprites. Drawing should not add velocity, decrement gameplay timers, or call a physics object’s Update() method. Camera coordinates explains the camera subtraction, while Drawable lifetime covers leaser ownership and cleanup.

RainWorldGame.Update() advances cameras, abstract simulation, world processes, rain, shortcuts, and active rooms while the game is active and unpaused. Active rooms receive Room.Update() and then Room.PausedUpdate(). During pause, the game still updates HUDs and calls PausedUpdate() for active rooms. Graphics also has paused paths. Choose a hook after inspecting the exact object family and test its pause behavior.

Work with BodyChunk history

global::BodyChunk exposes pos, lastPos, lastLastPos, optional setPos, vel, rad, and mass. Its update applies forces such as gravity and buoyancy, records position history, applies a queued position or integrates velocity, then handles enabled terrain and slope collision.

Changing vel asks the normal update path to carry an impulse into movement:

chunk.vel += impulse;

The correct hook side matters. Static inspection did not establish the best ordering for every object, grab state, or competing detour, so test the chosen call site.

HardSetPosition(Vector2) writes pos, lastPos, and lastLastPos together and updates a queued set position. Use it when a position change should start without an interpolation trail. It does not guarantee that the destination is free of terrain, resolve overlap, preserve constraints, or make a teleport safe.

MoveFromOutsideMyUpdate(bool eu, Vector2 moveTo) either changes pos immediately or queues setPos, based on the owner’s alternating update state. RelativeMoveFromOutsideMyUpdate applies the same rule to an offset. Pass the matching eu value from the surrounding object update. These helpers coordinate timing with BodyChunk.Update. They do not promise collision resolution at the destination.

Assigning only pos leaves the history fields at their old values. Render code that interpolates lastPos to pos can then draw a streak from the previous location. It can also bypass assumptions made by queued movement and constraints.

No simulation was run for this page. Test normal terrain, slopes, water, pause, slow time, lag, grabbed objects, room transitions, and multiplayer. Record update and graphics counts rather than converting update calls to elapsed seconds from the default value of 40.

Sources

  • Rain World v1.11.8, Steam app 312520, build 22785462. Assembly-CSharp.dll SHA-256 B6BE1D4E18CE219D21091B51564CB6A11C1E4106B41DE903EB8E58849CB16FDB.
  • Assembly-CSharp.dll: global::MainLoopProcess.RawUpdate(System.Single), global::MainLoopProcess.Update(), and global::MainLoopProcess.GrafUpdate(System.Single).
  • Assembly-CSharp.dll: global::RainWorldGame.RawUpdate(System.Single), global::RainWorldGame.Update(), and global::RainWorldGame.GrafUpdate(System.Single).
  • Assembly-CSharp.dll: global::BodyChunk.Update(), global::BodyChunk.HardSetPosition(UnityEngine.Vector2), global::BodyChunk.MoveFromOutsideMyUpdate(System.Boolean,UnityEngine.Vector2), and global::BodyChunk.RelativeMoveFromOutsideMyUpdate(System.Boolean,UnityEngine.Vector2).
  • Runtime reference records the same installed assembly baseline.