Use global::Room.PlaySound for a gameplay sound that belongs to a realized room. The room forwards the request to each game camera whose current room is that room. This keeps the call at the gameplay boundary and lets each matching camera’s global::VirtualMicrophone create its own sound object.

Rain World’s other audio paths have different owners:

NeedEntry point or ownerCaller responsibility
One sound at a world positionRoom.PlaySound with a Vector2Supply a current room, position, volume, and pitch
Sound attached to a body chunkRoom.PlaySound with a BodyChunkKeep the chunk and owning object valid
Persistent disembodied loopRoom.PlayDisembodiedLoopRetain the returned emitter and manage its lifetime
Room ambienceRoom settings and VirtualMicrophone.NewRoomAuthor and test the separate ambience configuration
MusicMusic.MusicPlayer eventsAccount for music policy, priority, and save state

Sound IDs select loaded triggers

global::SoundID is an ExtEnum<global::SoundID>. The built-in global::SoundID.Slugcat_Normal_Jump registers the string Slugcat_Normal_Jump. During global::SoundLoader.LoadSounds(), the loader sizes its trigger array from the registered SoundID values and matches those names against entries read from SoundEffects/Sounds.txt.

A registered enum value and a loaded sound trigger are related but distinct. Creating or finding a SoundID does not prove that its clips are available in a given asset setup. Custom trigger files, overrides, and packaging were outside this verification.

Play a positioned one-shot

The repository’s AudioCue example hooks global::Player.Update(System.Boolean) and plays one cue on a fresh pickup press. Its central call is:

self.room.PlaySound(
    SoundID.Slugcat_Normal_Jump,
    self.mainBodyChunk.pos,
    0.25f,
    1.2f);

The complete plugin stays in the example directory. Its GUID is rainworldmodding.audiocue and its plugin class is AudioCue. Before the call, it guards against NPC players, an unconscious player, deletion, shortcut travel, a missing room or body chunk, and incomplete input history. It also uses an input edge so holding pickup does not request the cue on every update. Hook lifecycle explains subscription cleanup and hook ordering.

The public source compiled through examples/build.ps1 with .NET SDK 10.0.400 against the installed baseline. Compilation checks the source, references, and hook signature. It does not show that the loader discovered the plugin or that the cue played in a game session.

The volume and pitch values above belong to this narrow cue. They are not recommended mix defaults. Check that the trigger is loaded, the cue is audible, the edge produces one extra request, and the result fits the rest of the game’s mix.

The global::Room.PlaySound(global::SoundID) overload accepts only the sound ID and delegates with pan 0f, volume 1f, and pitch 1f. The positioned overload forwards world position, volume, and pitch to matching camera microphones. global::VirtualMicrophone.PlaySound then checks whether sound is allowed and whether the clip data is ready before adding a positioned sound object.

The underlying pooled Unity AudioSource uses spatialBlend = 0f, while the microphone sound object still applies the game’s own position, pan, volume, and pitch handling. Static source does not establish perceived distance, stereo behavior, or suitable mix levels. Listen in the supported camera layouts.

Loops need an owner

global::Room.PlaySound has a BodyChunk overload that creates and returns a global::ChunkSoundEmitter. Its loop argument selects looping behavior. global::Room.PlayDisembodiedLoop creates a global::DisembodiedLoopEmitter, adds it to the room, sends it to matching camera microphones, and returns it. global::Room.PlayGenericSound follows the same broad pattern with a global::GenericLoopEmitter.

Retain the returned emitter when gameplay must change or stop it. Tie its lifetime to the gameplay object or state that requested the loop. The inspected source establishes creation and room registration. It did not establish a complete stop and destruction recipe, so test explicit stopping, owner deletion, room transitions, and emitter removal before releasing a loop feature.

Ambience and music use separate systems

When a microphone enters a room, global::VirtualMicrophone.NewRoom(global::Room) compares its existing ambience players with parent and local room settings. It updates close matches, destroys unmatched players, and creates missing ones. Ambient clip loading also has its own override and asset bundle paths. These facts make ambience a room configuration feature, rather than a long one-shot sound. The file format, path precedence, and reload behavior still need dedicated verification.

global::Music.MusicPlayer is a global::MainLoopProcess. Song requests pass through context, priority, threat, story record, and a limit of one song per cycle before a song is created or queued. Use room sounds for ordinary gameplay effects. Music event authoring needs separate evidence and tests for persistence and policy interactions.

Test one-shots and loops with multiple local cameras, room transitions, pause states, mod disable and re-enable, and other audio mods. No game session was launched for the source claims on this page.

Sources

  • Rain World v1.11.8, Steam app 312520, build 22785462. Assembly-CSharp.dll SHA-256 B6BE1D4E18CE219D21091B51564CB6A11C1E4106B41DE903EB8E58849CB16FDB.
  • Assembly-CSharp.dll: global::SoundID.Slugcat_Normal_Jump and global::SoundLoader.LoadSounds().
  • Assembly-CSharp.dll: global::Room.PlaySound(global::SoundID), global::Room.PlaySound(global::SoundID,System.Single,System.Single,System.Single), global::Room.PlaySound(global::SoundID,UnityEngine.Vector2,System.Single,System.Single), and global::Room.PlaySound(global::SoundID,global::BodyChunk,System.Boolean,System.Single,System.Single,System.Boolean).
  • Assembly-CSharp.dll: global::Room.PlayDisembodiedLoop(global::SoundID,System.Single,System.Single,System.Single) and global::Room.PlayGenericSound(...).
  • Assembly-CSharp.dll: global::VirtualMicrophone.PlaySound(global::SoundID,UnityEngine.Vector2,System.Single,System.Single), global::VirtualMicrophone.SoundObject..ctor(...), and global::VirtualMicrophone.NewRoom(global::Room).
  • Assembly-CSharp.dll: global::SoundLoader.LoadAllAmbientSounds() and global::SoundLoader.RequestAmbientAudioClip(System.String).
  • Assembly-CSharp.dll: global::Music.MusicPlayer..ctor(global::ProcessManager), global::Music.MusicPlayer.UpdateMusicContext(global::MainLoopProcess), global::Music.MusicPlayer.GameRequestsSong(global::MusicEvent), and global::Music.MusicPlayer.GameRequestsSongStop(global::StopMusicEvent).
  • AudioCue example source.
  • Runtime reference records the same installed assembly baseline and its verification limits.