Skip to content

Resources and Localization

This chapter introduces how to manage resource files in your Addon, including textures, models, sounds, and language localization.

Resource Directory Structure

Mod resource files are stored in the src/main/resources directory:

src/main/resources/
├── META-INF/
│   └── neoforge.mods.toml          # Mod metadata
├── assets/
│   └── myaddon/                    # Client resources
│       ├── blockstates/            # Block state definitions
│       ├── models/                 # Model files
│       │   ├── block/              # Block models
│       │   └── item/               # Item models
│       ├── textures/               # Texture files
│       │   ├── block/              # Block textures
│       │   ├── item/               # Item textures
│       │   ├── entity/             # Entity textures
│       │   └── gui/                # GUI textures
│       ├── sounds/                 # Sound files
│       ├── lang/                   # Language files
│       └── sounds.json             # Sound registration
└── data/
    └── myaddon/                    # Server data
        ├── recipe/                 # Recipes
        ├── loot_table/             # Loot tables
        ├── tags/                   # Tags
        └── advancement/            # Advancements

Texture Resources

Item Textures

Item texture files are located in assets/<modid>/textures/item/:

assets/myaddon/textures/item/
├── custom_item.png
├── custom_tool.png
└── custom_gem.png

Texture dimensions are typically 16x16 pixels.

Block Textures

Block texture files are located in assets/<modid>/textures/block/:

assets/myaddon/textures/block/
├── custom_block.png
├── custom_block_top.png
├── custom_block_side.png
└── custom_block_bottom.png

Entity Textures

Entity texture files are located in assets/<modid>/textures/entity/:

assets/myaddon/textures/entity/
├── custom_entity.png
└── custom_entity_overlay.png

Model Files

Item Models

Item model files are located in assets/<modid>/models/item/:

json
// assets/myaddon/models/item/custom_item.json
{
  "parent": "minecraft:item/generated",
  "textures": {
    "layer0": "myaddon:item/custom_item"
  }
}

For tool-type items:

json
// assets/myaddon/models/item/custom_tool.json
{
  "parent": "minecraft:item/handheld",
  "textures": {
    "layer0": "myaddon:item/custom_tool"
  }
}

Block Models

Block model files are located in assets/<modid>/models/block/:

json
// assets/myaddon/models/block/custom_block.json
{
  "parent": "minecraft:block/cube_all",
  "textures": {
    "all": "myaddon:block/custom_block"
  }
}

Multi-face texture blocks:

json
// assets/myaddon/models/block/custom_machine.json
{
  "parent": "minecraft:block/cube",
  "textures": {
    "up": "myaddon:block/custom_machine_top",
    "down": "myaddon:block/custom_machine_bottom",
    "north": "myaddon:block/custom_machine_front",
    "south": "myaddon:block/custom_machine_back",
    "east": "myaddon:block/custom_machine_side",
    "west": "myaddon:block/custom_machine_side"
  }
}

Block States

Block state files are located in assets/<modid>/blockstates/:

json
// assets/myaddon/blockstates/custom_block.json
{
  "variants": {
    "": {
      "model": "myaddon:block/custom_block"
    }
  }
}

Blocks with states:

json
// assets/myaddon/blockstates/custom_machine.json
{
  "variants": {
    "facing=north": { "model": "myaddon:block/custom_machine" },
    "facing=south": { "model": "myaddon:block/custom_machine", "y": 180 },
    "facing=east": { "model": "myaddon:block/custom_machine", "y": 90 },
    "facing=west": { "model": "myaddon:block/custom_machine", "y": 270 }
  }
}

Using Data Generators

It's recommended to use data generators to automatically generate resource files.

Model Generator

java
public class ModModelProvider extends BlockStateProvider {
    
    public ModModelProvider(PackOutput output, ExistingFileHelper helper) {
        super(output, MyAddon.MOD_ID, helper);
    }
    
    @Override
    protected void registerStatesAndModels() {
        // Simple block
        simpleBlockWithItem(ModBlocks.CUSTOM_BLOCK.get(), cubeAll(ModBlocks.CUSTOM_BLOCK.get()));
        
        // Block with facing
        horizontalBlock(ModBlocks.CUSTOM_MACHINE.get(), 
            models().orientable(
                "custom_machine",
                modLoc("block/custom_machine_side"),
                modLoc("block/custom_machine_front"),
                modLoc("block/custom_machine_top")
            )
        );
    }
}

Item Model Generator

java
public class ModItemModelProvider extends ItemModelProvider {
    
    public ModItemModelProvider(PackOutput output, ExistingFileHelper helper) {
        super(output, MyAddon.MOD_ID, helper);
    }
    
    @Override
    protected void registerModels() {
        // Simple item
        basicItem(ModItems.CUSTOM_ITEM.get());
        
        // Handheld tool
        handheldItem(ModItems.CUSTOM_TOOL.get());
        
        // Custom model
        getBuilder(ModItems.SPECIAL_ITEM.get().toString())
            .parent(new ModelFile.UncheckedModelFile("item/generated"))
            .texture("layer0", modLoc("item/special_item"));
    }
}

Language Localization

Language File Location

Language files are located in assets/<modid>/lang/:

assets/myaddon/lang/
├── en_us.json      # English (US)
├── zh_cn.json      # Simplified Chinese
├── zh_tw.json      # Traditional Chinese
└── ja_jp.json      # Japanese

Language File Format

json
// assets/myaddon/lang/en_us.json
{
  "item.myaddon.custom_item": "Custom Item",
  "item.myaddon.custom_tool": "Custom Tool",
  "block.myaddon.custom_block": "Custom Block",
  "block.myaddon.custom_machine": "Custom Machine",
  "itemGroup.myaddon": "My Addon",
  "tooltip.myaddon.custom_item": "A custom item from My Addon",
  "message.myaddon.success": "Operation successful!",
  "gui.myaddon.machine_title": "Machine"
}
json
// assets/myaddon/lang/zh_cn.json
{
  "item.myaddon.custom_item": "自定义物品",
  "item.myaddon.custom_tool": "自定义工具",
  "block.myaddon.custom_block": "自定义方块",
  "block.myaddon.custom_machine": "自定义机器",
  "itemGroup.myaddon": "我的附属",
  "tooltip.myaddon.custom_item": "来自我的附属的自定义物品",
  "message.myaddon.success": "操作成功!",
  "gui.myaddon.machine_title": "机器"
}

Translation Key Conventions

TypeFormatExample
Itemitem.<modid>.<name>item.myaddon.custom_item
Blockblock.<modid>.<name>block.myaddon.custom_block
Item GroupitemGroup.<modid>itemGroup.myaddon
Entityentity.<modid>.<name>entity.myaddon.custom_entity
Effecteffect.<modid>.<name>effect.myaddon.custom_effect
Enchantmentenchantment.<modid>.<name>enchantment.myaddon.custom_enchant
Tooltiptooltip.<modid>.<name>tooltip.myaddon.info
GUIgui.<modid>.<name>gui.myaddon.title
Messagemessage.<modid>.<name>message.myaddon.hello
Config<modid>.configuration.<name>myaddon.configuration.enable_feature

Using Data Generators for Language Files

java
public class ModLanguageProvider extends LanguageProvider {
    
    public ModLanguageProvider(PackOutput output, String locale) {
        super(output, MyAddon.MOD_ID, locale);
    }
    
    @Override
    protected void addTranslations() {
        // Items
        add(ModItems.CUSTOM_ITEM.get(), "Custom Item");
        add(ModItems.CUSTOM_TOOL.get(), "Custom Tool");
        
        // Blocks
        add(ModBlocks.CUSTOM_BLOCK.get(), "Custom Block");
        add(ModBlocks.CUSTOM_MACHINE.get(), "Custom Machine");
        
        // Item group
        add("itemGroup.myaddon", "My Addon");
        
        // Custom translations
        add("tooltip.myaddon.custom_item", "A custom item from My Addon");
        add("message.myaddon.success", "Operation successful!");
    }
}

Using Translations in Code

java
// Use Component to create translatable text
Component message = Component.translatable("message.myaddon.success");
player.displayClientMessage(message, true);

// Translation with parameters
Component formatted = Component.translatable("message.myaddon.welcome", player.getName());

// Item names automatically use translation keys
// item.myaddon.custom_item is automatically applied

Sound Resources

Adding Sound Files

Sound files are located in assets/<modid>/sounds/:

assets/myaddon/sounds/
├── custom_sound.ogg
├── machine_start.ogg
└── machine_stop.ogg

Sound files must be in .ogg format.

Registering Sounds

Create assets/<modid>/sounds.json:

json
{
  "custom_sound": {
    "sounds": ["myaddon:custom_sound"]
  },
  "machine": {
    "sounds": [
      {
        "name": "myaddon:machine_start",
        "stream": false
      }
    ]
  },
  "ambient": {
    "sounds": [
      {
        "name": "myaddon:ambient_1",
        "volume": 0.5
      },
      {
        "name": "myaddon:ambient_2",
        "volume": 0.5
      }
    ]
  }
}

Registering Sound Events in Code

java
public class ModSounds {
    public static final DeferredRegister<SoundEvent> SOUNDS = 
        DeferredRegister.create(Registries.SOUND_EVENT, MyAddon.MOD_ID);
    
    public static final Supplier<SoundEvent> CUSTOM_SOUND = SOUNDS.register(
        "custom_sound",
        () -> SoundEvent.createVariableRangeEvent(MyAddon.of("custom_sound"))
    );
    
    public static final Supplier<SoundEvent> MACHINE_START = SOUNDS.register(
        "machine",
        () -> SoundEvent.createVariableRangeEvent(MyAddon.of("machine"))
    );
    
    public static void register(IEventBus bus) {
        SOUNDS.register(bus);
    }
}

Playing Sounds

java
// Play on server side
level.playSound(null, pos, ModSounds.CUSTOM_SOUND.get(), SoundSource.BLOCKS, 1.0f, 1.0f);

// Play on client side
level.playLocalSound(pos, ModSounds.CUSTOM_SOUND.get(), SoundSource.BLOCKS, 1.0f, 1.0f, false);

// Play for player
player.playSound(ModSounds.CUSTOM_SOUND.get(), 1.0f, 1.0f);

GUI Textures

Container GUI Textures

assets/myaddon/textures/gui/
├── container/
│   ├── custom_machine.png    # Container background
│   └── slots.png             # Slot textures
└── widgets/
    └── buttons.png           # Button textures

Using GUI Textures in Code

java
public class CustomMachineScreen extends AbstractContainerScreen<CustomMachineMenu> {
    private static final ResourceLocation TEXTURE = 
        MyAddon.of("textures/gui/container/custom_machine.png");
    
    @Override
    protected void renderBg(GuiGraphics graphics, float partialTick, int mouseX, int mouseY) {
        graphics.blit(TEXTURE, leftPos, topPos, 0, 0, imageWidth, imageHeight);
    }
}

Resource Pack Overrides

Players can override mod textures and language files through resource packs. Simply use the same path in the resource pack:

resourcepack/
└── assets/
    └── myaddon/
        └── textures/
            └── item/
                └── custom_item.png  # Overrides original texture

Best Practices

  1. Texture Naming

    • Use lowercase letters and underscores
    • Names should be descriptive
    • Keep consistent with registry names
  2. Texture Dimensions

    • Item/block textures: 16x16 pixels
    • Can use higher resolutions (32x32, 64x64, etc.), but keep powers of 2
  3. Translation Completeness

    • Ensure all visible text has translation keys
    • Provide at least English translations as fallback
  4. Use Data Generators

    • Automatic generation reduces errors
    • Facilitates batch modifications
  5. Resource Compression

    • Optimize PNG file sizes
    • Use appropriate audio bitrates
  6. Test Resources

    • Test in different language environments
    • Check that textures display correctly

Released under the CC-BY-NC-SA 4.0 License.