Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Chapter 30 — Custom Sounds and Language

What You’ll Build

By the end of this chapter your resource pack will play a sound you chose (your own .ogg audio file) through a sound event you registered yourself, fired by the /playsound command and even by an advancement. You’ll also add a language file, which is how Minecraft turns a short code like item.mypack.power_gem into readable words such as “Power Gem” on every player’s screen, in their own language. Then you’ll wire the two together: a custom advancement that, when a player triggers it, runs a function that plays your sound and shows a styled, translated message. This is the chapter that closes Part VIII, so it leans on the resource pack you built in Chapter 28: the assets/ folder lives there, not in data/.

Concepts

A sound event is a name, not a file

You might expect /playsound to take the name of an audio file. It doesn’t. In Java Edition, /playsound takes a sound event, a registered name like entity.pig.ambient that the sound system looks up to decide which audio file (or files) to actually play. The list that maps sound-event names to audio files is a single file called sounds.json.

From the reference: sounds.json … is a file used by the sound system in resource packs which tells the sound system what sound files to play when a sound event is triggered.” And the /playsound page is blunt about it: the command “strictly uses the events defined in sounds.json … and thus a resource pack adding new sound files must define events for them.”

So to add a custom sound you do two things: drop an audio file into your pack, and register a sound event in sounds.json that points at it. The command never names the file; it names the event.

OGG: the one audio format

Minecraft sounds are OGG Vorbis files, the ones ending in .ogg. The resource pack reference lists the sounds directory as holding .ogg files that provide audio such as music and sound effects for the game.” MP3 and WAV won’t work; the game only reads .ogg. Most free audio editors (Audacity is a common one) can export to .ogg.

Modern Minecraft. This hasn’t changed in years, but it still trips people up: there is no /playsound somefile.ogg. The filename is invisible to commands. Everything goes through the event you register in sounds.json. If you rename your .ogg, you only update sounds.json; the command that plays it never changes.

A language file maps codes to words

Minecraft almost never hard-codes the words you see. Instead it uses a translation key, a short code like block.minecraft.stone, and looks up the actual words in a language file for whatever language the player has selected. From the reference: block.minecraft.stone is the ID of the text used for the name of the stone block, and its translation in the en_us language is Stone.” (en_us is the code for U.S. English.)

A language file is just a JSON object full of "key": "value" pairs. You can invent your own keys for your own items and messages, put the words in a language file, and every player sees the right words for their language, changed in just one place.

Walkthrough

Everything in this chapter goes in your resource pack, the one from Chapter 28. Its top folder is assets/, and inside it is your namespace folder. We’ll keep using the namespace mypack, so paths look like assets/mypack/.... (Remember the slogan from Chapter 7: data packs change behavior; resource packs change appearance, and sound.)

Step 1 — Put an OGG file in your pack

Audio files live in a sounds folder inside your namespace. Pick or make a short .ogg clip (say a little chime) and save it here:

assets/mypack/sounds/power_gem_chime.ogg

That’s the whole file-placement rule from the reference: the sounds/ directory under your namespace holds the .ogg files. You can make subfolders if you like (the path just uses forward slashes), but one file in sounds/ is enough to start.

What Went Wrong? If your audio won’t play and it’s a .wav or .mp3 you renamed to .ogg, that’s the problem: renaming doesn’t convert it. Re-export it as a real OGG Vorbis file from an audio editor.

Step 2 — Register a sound event in sounds.json

Now tell the sound system that this file exists, by giving it an event name. The sounds.json file sits directly under your namespace folder:

assets/mypack/sounds.json

{
  "power_gem_chime": {
    "sounds": [
      "mypack:power_gem_chime"
    ]
  }
}

Read this against the reference structure. The root is an object. Each key is a Sound Event, here power_gem_chime. Its value is an object, and the important field is sounds, “the sound files this sound event uses,” a list. Each entry in the list is a path “from the namespace/sounds folder (excluding the .ogg file extension).” So mypack:power_gem_chime means: look in mypack’s sounds/ folder for power_gem_chime.ogg.

Two details the reference is strict about:

  • No .ogg in the path, and use forward slashes (mob/cat/purr, never backslashes).
  • The namespace. A bare path like "power_gem_chime" “defaults to minecraft, so it would look in the vanilla pack and fail. Prepend your namespace and a colon ("mypack:power_gem_chime") so it looks in your pack. This is the single most common custom-sound mistake.

There’s one more namespace rule for the event name itself. The event you just made is fully named mypack:power_gem_chime, because (per the reference) “to get a different namespace than minecraft the file must be under a different namespace.” Your sounds.json is under assets/mypack/, so every event in it automatically belongs to the mypack namespace. You do not write mypack: in front of the key inside the file; the folder already supplies it.

Step 3 — Adding fields: volume, pitch, subtitle, weight

The simple string form is enough for most sounds. But an entry can also be an object when you want to tune it. Here’s a fuller version:

assets/mypack/sounds.json

{
  "power_gem_chime": {
    "subtitle": "subtitles.mypack.power_gem_chime",
    "sounds": [
      {
        "name": "mypack:power_gem_chime",
        "volume": 1.0,
        "pitch": 1.0,
        "weight": 1,
        "stream": false
      }
    ]
  }
}

Every field here is straight from the reference:

  • subtitle“Translation key for the subtitle of the sound,” the line that shows in the corner when subtitles are turned on. It’s a translation key, so we’ll define it in the language file in Step 5. “If not specified, the sound event is not displayed in closed captions.”
  • name — the same path as the string form (no .ogg, with your namespace).
  • volume“a decimal greater than 0.0 … If undefined, defaults to 1.0.”
  • pitch“Plays the pitch at the specified value … defaults to 1.0, but higher and lower values can be chosen.” Higher is squeakier and faster, lower is deeper and slower.
  • weight“The chance that this sound is selected to play.” It matters only when you list several sounds: a sound with weight 2 is “like placing in the name twice.”
  • stream — leave it false for short effects. The reference recommends true only “for sounds that have a duration longer than a few seconds to avoid lag” (long music).

Under the Hood (skippable). A sound event can list several sounds and the game picks one at random, weighted, each time. That’s why a pig doesn’t make the exact same noise twice in a row: entity.pig.ambient has many sound files behind it. You can do the same: list a few chimes and your gem will sound a little different each pickup.

Under the Hood (skippable). One sharp edge from the reference: an audio file with one channel (mono) plays locationally: it gets quieter as you walk away. A two-channel (stereo) file plays at constant volume no matter where you are, like music. For a sound that should come “from” a place in the world, use a mono file.

Step 4 — Play it with /playsound

You met /playsound back in Chapter 2 with vanilla sounds. The exact same command plays your new event. The game can’t tell the difference, because to it an event is an event. We write it in a function, as always (Chapter 9):

data/mypack/function/play_chime.mcfunction

# Play our custom chime to the nearest player, from the master sound category
playsound mypack:power_gem_chime master @p

The reference syntax is playsound <sound> [<source>] [<targets>] [<pos>] [<volume>] [<pitch>] [<minVolume>]. The first argument, <sound>, “should be a Sound Event defined in sounds.json,” and “resource packs may add their own events to sounds.json; the command successfully plays these.” That’s our mypack:power_gem_chime.

The <source> (master, music, record, weather, block, hostile, neutral, player, ambient, voice, or ui) picks which volume slider in the player’s settings controls it. master is always safe. After that, @p is the target. Reload and run the function (/reload, then /function mypack:play_chime) and you should hear your chime.

Two more from the reference, both optional:

  • <volume> doesn’t make the sound louder above 1; it multiplies the audible range (the radius is 16 blocks at volume 1). Below 1, it does get quieter.
  • <pitch> “values less than 0.5 are equivalent to 0.5,” and the pitch value also changes the duration: lower is slower, higher is faster.

Try It! Stop a long sound early with its sibling command, stopsound <targets> [<source>] [<sound>]. For example, in a function: stopsound @a master mypack:power_gem_chime. With no sound given it “stops all sounds,” and a <source> of * stops every category at once.

Step 5 — Add a language file

Now the words. A language file is named for its language code and lives in the lang folder. The resource pack reference lists lang as holding <language code>.json files containing translations of text.” We’ll do U.S. English, en_us:

assets/mypack/lang/en_us.json

{
  "item.mypack.power_gem": "Power Gem",
  "subtitles.mypack.power_gem_chime": "Gem chimes",
  "mypack.message.gem_found": "You found a %s!"
}

This is exactly the structure the reference gives: “an object containing ID and translation pairs.” The key is a translation key you invent; the value is the words shown when that key is used. Three keys here, doing three different jobs:

  • item.mypack.power_gem — a name for a custom item (more on this below).
  • subtitles.mypack.power_gem_chime — the subtitle we referenced from sounds.json in Step 3. Now that it’s defined, players with subtitles on will see “Gem chimes” when the sound plays.
  • mypack.message.gem_found — a message we’ll show in chat, with a slot in it.

That %s is a placeholder, a slot the game fills in later. The reference: placeholders “to be replaced by other text or numbers later can also be used … using the with of a translatable text component,” written as %s. We’ll fill it next.

Under the Hood (skippable). Naming keys with dots (item.mypack.power_gem) is just a convention to keep them tidy and unique; to the game it’s only a string. Vanilla follows the same pattern (block.minecraft.stone), so copying it keeps your keys from clashing with anyone else’s. The reference also notes language files “are merged with other selected packs,” so you only need to list the keys you add; everything else still comes from vanilla.

Step 6 — Use the translation in a text component

A language file does nothing on its own; something has to use the key. The way you reach it is the translate text component you met in Chapter 5. Instead of writing the words directly, you give the key:

data/mypack/function/announce_gem.mcfunction

# Show the translated message, filling its %s slot with the item's translated name
tellraw @a {"translate": "mypack.message.gem_found", "with": [{"translate": "item.mypack.power_gem"}]}

Here’s the connection, straight from the reference’s description of the translatable content type. The translate field is “a translation identifier, corresponding to the identifiers found in loaded language files.” The with field is “a list of text components to be inserted into slots in the translation text.” Our message "You found a %s!" has one slot; with supplies one component, itself a translate for the gem’s name. A player in English sees “You found a Power Gem!” A player in another language sees the same sentence translated, if they (or you) provided those keys for that language.

The reference even uses the game’s own example to show how slots line up: the built-in English file contains "chat.type.advancement.task": "%s has made the advancement %s", with two %s slots, filled by two components in with (the player, then the advancement). Yours works the same way with one slot.

Two safety nets the reference gives you:

  • fallback“If no corresponding translation can be found, this is used as the translated text.” Add "fallback": "You found a gem!" and even a player whose pack is missing will see readable words instead of the raw key.
  • If there’s no translation and no fallback, “the identifier itself is used”: the player just sees mypack.message.gem_found on screen. Ugly, but a useful clue that a key is missing.

Step 7 — Translated item names (the payoff)

This is why language files matter for items. Recall from Chapter 22 that an item can carry an item_name component. If you set item_name to a translate component, the displayed name comes from your language file:

data/mypack/function/give_gem.mcfunction

# Give a named gem whose name comes from the language file key item.mypack.power_gem
give @s emerald[item_name={"translate":"item.mypack.power_gem"}]

Now the item shows as “Power Gem”, and to a French player whose pack defines item.mypack.power_gem as "Gemme de puissance", it shows in French automatically. That’s the whole point of routing names through a language file instead of typing them in: one item, correct in every language, changed in one place.

Practice — a sound that plays when your advancement triggers

Let’s wire all of Part VIII’s threads together: an advancement (Chapter 19) that, when a player earns it, runs a function that plays your custom sound and shows your translated message.

First the function the advancement will launch:

data/mypack/function/gem_reward.mcfunction

# Plays the custom chime and announces it — runs as/at the player who earned the advancement
playsound mypack:power_gem_chime master @s
tellraw @s {"translate": "mypack.message.gem_found", "with": [{"translate": "item.mypack.power_gem"}], "fallback": "You found a gem!"}

Now the advancement that runs it. We’ll keep it simple (it triggers the first time the player picks up, or otherwise gains, an emerald) and we hide its display so it is a pure event detector (Chapter 19). The key piece is the rewards.function field, which the advancement reference confirms runs a function when the advancement is granted:

data/mypack/advancement/found_gem.json

{
  "criteria": {
    "got_emerald": {
      "trigger": "minecraft:inventory_changed",
      "conditions": {
        "items": [
          {
            "items": [
              "minecraft:emerald"
            ]
          }
        ]
      }
    }
  },
  "rewards": {
    "function": "mypack:gem_reward"
  }
}

(The doubled items looks odd but matches the reference exactly: the outer items is a list of item checks, and inside each one the inner items is a list of allowed item IDs, here just minecraft:emerald.)

Recall from Chapter 19 that the reward function runs as the player who earned the advancement and at their position, so inside gem_reward, @s is that player. That’s why we used @s for both the playsound and the tellraw: the sound plays to them, and the message goes to them. Load both your data pack and resource pack, pick up an emerald in a fresh test world, and you should hear your chime and see “You found a Power Gem!”

Try It! Add a subtitle payoff: with subtitles turned on (Options → Music & Sound → Show Subtitles), the subtitles.mypack.power_gem_chime key you defined makes “Gem chimes” appear in the corner each time the sound fires, no extra command needed.

Try It! Make the gem sound a little different each time. Put two or three short chime .ogg files in sounds/, list all of them in the event’s sounds array, and give the rare one a low weight. The game will pick one at random, weighted, every pickup.

What Can Go Wrong

  • The whole pack goes silent and vanilla sounds come back. The sounds reference warns that a single bad entry can make “the entire sounds.json being ignored, in favor of vanilla sounds.” The usual cause is a sound path that doesn’t resolve (wrong namespace, a stray .ogg on the end, a backslash) or a volume/pitch of 0. Fix the one broken entry and the rest come back.

  • /playsound says nobody could hear it. From the reference, the command fails when the target is out of range and minVolume is 0, or when the named event simply doesn’t exist. Double-check the event name matches the key in sounds.json exactly, including the mypack: namespace. Remember a bare name looks in minecraft, not your pack.

  • The screen shows the raw key, like item.mypack.power_gem, instead of words. That’s the reference’s “the identifier itself is used as the translated text”: your lang file is missing the key, or the resource pack isn’t actually loaded, or the player’s language isn’t en_us and you only wrote en_us.json. Add a fallback so a miss degrades to readable words instead of a code.

What You Know Now — Part VIII recap

Part VIII gave appearance to the behavior you built in Parts I–VI. You can now:

  • Build a resource pack and bundle it with your data pack (Chapter 28).
  • Give items custom models and textures, including models that change with the item’s state (Chapter 29).
  • Register custom sound events in sounds.json, drop .ogg audio into sounds/, and play them with /playsound, even from an advancement reward (Chapter 30).
  • Route every name and message through a language file, so your pack reads correctly in any language and you change wording in exactly one place.

You can now build a content pack that does new things and looks and sounds like its own thing, which is exactly what Chapter 34’s complete content-pack project will pull together.