Template: Ruby Ore & Tools
This is a self-contained template for adding a full ore-to-tools pipeline to LCE. Copy it, swap “Ruby” for your material name, adjust the numbers, and you have a working mod.
We are building all of this from scratch:
- Ruby ore block (spawns underground)
- Ruby gem item (drops from the ore)
- Ruby storage block (9 gems to 1 block, reversible)
- Ruby tool tier (sits between iron and diamond)
- All 5 ruby tools (sword, pickaxe, shovel, axe, hoe)
- Ruby armor material with all 4 pieces
- Crafting, smelting, and storage recipes
- Ore world generation with configurable Y levels and vein size
- Texture registration for everything
If you have not set up a build environment yet, start with Getting Started.
1. Plan your IDs
Section titled “1. Plan your IDs”Every tile and item needs a unique numeric ID. Tiles occupy IDs 0 through 4095. Items offset by 256 internally, so when you pass 151 to an Item constructor, the real ID becomes 407.
Pick a block of unused IDs and write them down before you touch any code. Here is the full set for this template:
| Name | Type | Constructor arg | Final ID |
|---|---|---|---|
| Ruby Ore | Tile | 160 | 160 |
| Ruby Block | Tile | 161 | 161 |
| Ruby (gem) | Item | 151 | 407 |
| Ruby Sword | Item | 152 | 408 |
| Ruby Shovel | Item | 153 | 409 |
| Ruby Pickaxe | Item | 154 | 410 |
| Ruby Axe | Item | 155 | 411 |
| Ruby Hoe | Item | 156 | 412 |
| Ruby Helmet | Item | 157 | 413 |
| Ruby Chestplate | Item | 158 | 414 |
| Ruby Leggings | Item | 159 | 415 |
| Ruby Boots | Item | 160 | 416 |
Scan Tile.h and Item.h for existing ID constants to make sure nothing overlaps.
2. The ore block
Section titled “2. The ore block”The ore is a Tile subclass that drops a gem item instead of itself, awards XP, and supports Fortune.
RubyOreTile.h
Section titled “RubyOreTile.h”Create Minecraft.World/RubyOreTile.h:
#pragma once#include "Tile.h"
class Random;class Level;
class RubyOreTile : public Tile{public: RubyOreTile(int id);
virtual int getResource(int data, Random *random, int playerBonusLevel); virtual int getResourceCount(Random *random); virtual int getResourceCountForLootBonus(int bonusLevel, Random *random); virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonusLevel);
protected: virtual int getSpawnResourcesAuxValue(int data);};RubyOreTile.cpp
Section titled “RubyOreTile.cpp”Create Minecraft.World/RubyOreTile.cpp:
#include "stdafx.h"#include "RubyOreTile.h"#include "net.minecraft.world.item.h"#include "net.minecraft.world.level.h"
RubyOreTile::RubyOreTile(int id) : Tile(id, Material::stone){}
int RubyOreTile::getResource(int data, Random *random, int playerBonusLevel){ // Return the gem item ID, not the block itself. // Change this to return `id` if your ore should drop as a block (like iron/gold). return Item::ruby_Id;}
int RubyOreTile::getResourceCount(Random *random){ // How many items drop per block. 1 is standard for most ores. return 1;}
int RubyOreTile::getResourceCountForLootBonus(int bonusLevel, Random *random){ // Fortune enchantment logic. Same formula the vanilla ores use. if (bonusLevel > 0) { int bonus = random->nextInt(bonusLevel + 2) - 1; if (bonus < 0) bonus = 0; return getResourceCount(random) * (bonus + 1); } return getResourceCount(random);}
void RubyOreTile::spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonusLevel){ Tile::spawnResources(level, x, y, z, data, odds, playerBonusLevel);
// XP orbs on mine. Vanilla ranges: coal 0-2, diamond/emerald 3-7, lapis/quartz 2-5. int xp = Mth::nextInt(level->random, 3, 7); popExperience(level, x, y, z, xp);}
int RubyOreTile::getSpawnResourcesAuxValue(int data){ // Aux value for the dropped item. 0 for most ores. // Lapis returns DyePowderItem::BLUE here because it drops dye. return 0;}The five methods you care about:
getResource()controls what drops (gem vs. block)getResourceCount()controls how many dropgetResourceCountForLootBonus()handles Fortune scalingspawnResources()handles XP orb spawninggetSpawnResourcesAuxValue()sets the aux/data value on the dropped item
3. Register tiles
Section titled “3. Register tiles”Tile.h
Section titled “Tile.h”Add these with the other static members:
// Forward declaration (near the top)class RubyOreTile;
// Static members (inside the Tile class)static Tile *rubyOre;static const int rubyOre_Id = 160;
static Tile *rubyBlock;static const int rubyBlock_Id = 161;Tile.cpp
Section titled “Tile.cpp”Static definitions (near the other Tile * defs):
Tile *Tile::rubyOre = NULL;Tile *Tile::rubyBlock = NULL;const int definitions (at the bottom with the rest):
const int Tile::rubyOre_Id;const int Tile::rubyBlock_Id;Inside Tile::staticCtor():
// Ruby OreTile::rubyOre = (new RubyOreTile(Tile::rubyOre_Id)) ->setDestroyTime(3.0f) ->setExplodeable(5) ->setSoundType(Tile::SOUND_STONE) ->setTextureName(L"oreRuby") ->setDescriptionId(IDS_TILE_RUBY_ORE) ->setUseDescriptionId(IDS_DESC_RUBY_ORE);
// Ruby Block (storage, like diamond block)Tile::rubyBlock = (new MetalTile(Tile::rubyBlock_Id)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_block, Item::eMaterial_diamond) ->setDestroyTime(5.0f) ->setExplodeable(10) ->setSoundType(Tile::SOUND_METAL) ->setTextureName(L"blockRuby") ->setDescriptionId(IDS_TILE_RUBY_BLOCK) ->setUseDescriptionId(IDS_DESC_RUBY_BLOCK);MetalTile is the same class that gold and diamond storage blocks use. It is just a solid block with no special logic. See Adding Blocks for more on tile properties.
4. The gem item
Section titled “4. The gem item”The gem itself is a plain Item with no special behavior. Think diamonds and emeralds.
Item.h
Section titled “Item.h”static Item *ruby;static const int ruby_Id = 407;Item.cpp
Section titled “Item.cpp”Static definition:
Item *Item::ruby = NULL;Inside Item::staticCtor():
Item::ruby = (new Item(151)) ->setBaseItemTypeAndMaterial(eBaseItemType_treasure, eMaterial_diamond) ->setTextureName(L"ruby") ->setDescriptionId(IDS_ITEM_RUBY) ->setUseDescriptionId(IDS_DESC_RUBY);Constructor arg 151 + offset 256 = final ID 407. See Adding Items for more on the item system.
5. Tool tier
Section titled “5. Tool tier”Tool tiers control mining speed, damage, durability, and enchantability. Here are the vanilla tiers for reference:
// _Tier(level, uses, speed, damage, enchantValue)WOOD = new _Tier(0, 59, 2, 0, 15);STONE = new _Tier(1, 131, 4, 1, 5);IRON = new _Tier(2, 250, 6, 2, 14);DIAMOND = new _Tier(3, 1561, 8, 3, 10);GOLD = new _Tier(0, 32, 12, 0, 22);| Field | What it does |
|---|---|
level | Mining level. 0 = wood/gold, 1 = stone, 2 = iron, 3 = diamond |
uses | Durability (total uses before breaking) |
speed | Mining speed multiplier |
damage | Base attack damage bonus |
enchantValue | How well it accepts enchantments (higher = better) |
Item.h
Section titled “Item.h”Inside the _Tier class:
static const _Tier *RUBY;Item.cpp
Section titled “Item.cpp”With the other tier definitions:
const _Tier *_Tier::RUBY = new _Tier(2, 750, 7, 2, 12);Ruby sits between iron and diamond: mining level 2, 750 durability, speed 7, damage bonus 2, enchant value 12. Tweak these to taste.
Repair material
Section titled “Repair material”So that ruby tools can be repaired with rubies on an anvil, add a check to Tier::getTierItemId() in Item.cpp:
int Tier::getTierItemId(){ // ... existing checks for WOOD, STONE, IRON, DIAMOND, GOLD ... if (this == RUBY) return Item::ruby_Id; return -1;}This covers all tools that use the RUBY tier in one place.
6. Register all 5 tools
Section titled “6. Register all 5 tools”Item.h
Section titled “Item.h”static Item *sword_ruby;static Item *shovel_ruby;static Item *pickAxe_ruby;static Item *hatchet_ruby;static Item *hoe_ruby;
static const int sword_ruby_Id = 408;static const int shovel_ruby_Id = 409;static const int pickAxe_ruby_Id = 410;static const int hatchet_ruby_Id = 411;static const int hoe_ruby_Id = 412;Item.cpp
Section titled “Item.cpp”Static definitions:
Item *Item::sword_ruby = NULL;Item *Item::shovel_ruby = NULL;Item *Item::pickAxe_ruby = NULL;Item *Item::hatchet_ruby = NULL;Item *Item::hoe_ruby = NULL;Inside Item::staticCtor():
Item::sword_ruby = (new WeaponItem(152, _Tier::RUBY)) ->setBaseItemTypeAndMaterial(eBaseItemType_sword, eMaterial_diamond) ->setTextureName(L"swordRuby") ->setDescriptionId(IDS_ITEM_SWORD_RUBY) ->setUseDescriptionId(IDS_DESC_SWORD);
Item::shovel_ruby = (new ShovelItem(153, _Tier::RUBY)) ->setBaseItemTypeAndMaterial(eBaseItemType_shovel, eMaterial_diamond) ->setTextureName(L"shovelRuby") ->setDescriptionId(IDS_ITEM_SHOVEL_RUBY) ->setUseDescriptionId(IDS_DESC_SHOVEL);
Item::pickAxe_ruby = (new PickaxeItem(154, _Tier::RUBY)) ->setBaseItemTypeAndMaterial(eBaseItemType_pickaxe, eMaterial_diamond) ->setTextureName(L"pickaxeRuby") ->setDescriptionId(IDS_ITEM_PICKAXE_RUBY) ->setUseDescriptionId(IDS_DESC_PICKAXE);
Item::hatchet_ruby = (new HatchetItem(155, _Tier::RUBY)) ->setBaseItemTypeAndMaterial(eBaseItemType_hatchet, eMaterial_diamond) ->setTextureName(L"hatchetRuby") ->setDescriptionId(IDS_ITEM_HATCHET_RUBY) ->setUseDescriptionId(IDS_DESC_HATCHET);
Item::hoe_ruby = (new HoeItem(156, _Tier::RUBY)) ->setBaseItemTypeAndMaterial(eBaseItemType_hoe, eMaterial_diamond) ->setTextureName(L"hoeRuby") ->setDescriptionId(IDS_ITEM_HOE_RUBY) ->setUseDescriptionId(IDS_DESC_HOE);Each tool class (WeaponItem, PickaxeItem, ShovelItem, HatchetItem, HoeItem) takes the item ID and a tier reference. The setUseDescriptionId reuses the generic tool descriptions since “A sword” or “A pickaxe” is the same regardless of material.
7. Armor material and pieces
Section titled “7. Armor material and pieces”ArmorMaterial
Section titled “ArmorMaterial”Armor materials define per-slot protection, durability, and enchant value. Vanilla materials for reference:
// _ArmorMaterial(durabilityMultiplier, slotProtections[], enchantValue)CLOTH = new _ArmorMaterial(5, clothArray, 15); // leatherCHAIN = new _ArmorMaterial(15, chainArray, 12);IRON = new _ArmorMaterial(15, ironArray, 9);GOLD = new _ArmorMaterial(7, goldArray, 25);DIAMOND = new _ArmorMaterial(33, diamondArray, 10);The slotProtections array is {helmet, chestplate, leggings, boots}. Durability per slot is durabilityMultiplier * baseHealth, where base health is {11, 16, 15, 13}.
ArmorItem.h
Section titled “ArmorItem.h”static const int rubyArray[];static const _ArmorMaterial *RUBY;ArmorItem.cpp
Section titled “ArmorItem.cpp”const int _ArmorMaterial::rubyArray[] = {3, 7, 5, 3};const _ArmorMaterial *_ArmorMaterial::RUBY = new _ArmorMaterial(25, _ArmorMaterial::rubyArray, 12);That gives us 18 total defense (3+7+5+3), multiplier 25, enchant value 12. Between iron and diamond for both protection and durability.
| Piece | Base Health | x25 | Durability |
|---|---|---|---|
| Helmet | 11 | 25 | 275 |
| Chestplate | 16 | 25 | 400 |
| Leggings | 15 | 25 | 375 |
| Boots | 13 | 25 | 325 |
Add a repair check in ArmorMaterial::getTierItemId():
int ArmorMaterial::getTierItemId(){ // ... existing checks ... if (this == RUBY) return Item::ruby_Id; return -1;}Armor pieces in Item.h
Section titled “Armor pieces in Item.h”static ArmorItem *helmet_ruby;static ArmorItem *chestplate_ruby;static ArmorItem *leggings_ruby;static ArmorItem *boots_ruby;
static const int helmet_ruby_Id = 413;static const int chestplate_ruby_Id = 414;static const int leggings_ruby_Id = 415;static const int boots_ruby_Id = 416;Armor pieces in Item.cpp
Section titled “Armor pieces in Item.cpp”Static definitions:
ArmorItem *Item::helmet_ruby = NULL;ArmorItem *Item::chestplate_ruby = NULL;ArmorItem *Item::leggings_ruby = NULL;ArmorItem *Item::boots_ruby = NULL;Inside Item::staticCtor():
Item::helmet_ruby = (ArmorItem *)( (new ArmorItem(157, _ArmorMaterial::RUBY, 5, ArmorItem::SLOT_HEAD)) ->setBaseItemTypeAndMaterial(eBaseItemType_helmet, eMaterial_diamond) ->setTextureName(L"helmetRuby") ->setDescriptionId(IDS_ITEM_HELMET_RUBY) ->setUseDescriptionId(IDS_DESC_HELMET_RUBY));
Item::chestplate_ruby = (ArmorItem *)( (new ArmorItem(158, _ArmorMaterial::RUBY, 5, ArmorItem::SLOT_TORSO)) ->setBaseItemTypeAndMaterial(eBaseItemType_chestplate, eMaterial_diamond) ->setTextureName(L"chestplateRuby") ->setDescriptionId(IDS_ITEM_CHESTPLATE_RUBY) ->setUseDescriptionId(IDS_DESC_CHESTPLATE_RUBY));
Item::leggings_ruby = (ArmorItem *)( (new ArmorItem(159, _ArmorMaterial::RUBY, 5, ArmorItem::SLOT_LEGS)) ->setBaseItemTypeAndMaterial(eBaseItemType_leggings, eMaterial_diamond) ->setTextureName(L"leggingsRuby") ->setDescriptionId(IDS_ITEM_LEGGINGS_RUBY) ->setUseDescriptionId(IDS_DESC_LEGGINGS_RUBY));
Item::boots_ruby = (ArmorItem *)( (new ArmorItem(160, _ArmorMaterial::RUBY, 5, ArmorItem::SLOT_FEET)) ->setBaseItemTypeAndMaterial(eBaseItemType_boots, eMaterial_diamond) ->setTextureName(L"bootsRuby") ->setDescriptionId(IDS_ITEM_BOOTS_RUBY) ->setUseDescriptionId(IDS_DESC_BOOTS_RUBY));The ArmorItem constructor takes (id, material, renderIndex, slot). Render index 5 is a new custom slot for our ruby armor textures. The (ArmorItem *) cast is needed because the chained set* calls return Item *.
8. Recipes
Section titled “8. Recipes”Tool recipes
Section titled “Tool recipes”In ToolRecipies.cpp, inside ToolRecipies::_init(), add after the existing gold entries:
ADD_OBJECT(map[0], Item::ruby);ADD_OBJECT(map[1], Item::pickAxe_ruby);ADD_OBJECT(map[2], Item::shovel_ruby);ADD_OBJECT(map[3], Item::hatchet_ruby);ADD_OBJECT(map[4], Item::hoe_ruby);Weapon recipes
Section titled “Weapon recipes”In WeaponRecipies.cpp, inside WeaponRecipies::_init():
ADD_OBJECT(map[0], Item::ruby);ADD_OBJECT(map[1], Item::sword_ruby);The recipe system auto-generates the standard stick + material patterns for you. See Adding Recipes for details on how the shaped recipe arrays work.
Armor recipes
Section titled “Armor recipes”In ArmorRecipes.cpp, inside ArmorRecipes::_init():
ADD_OBJECT(map[0], Item::ruby);ADD_OBJECT(map[1], Item::helmet_ruby);ADD_OBJECT(map[2], Item::chestplate_ruby);ADD_OBJECT(map[3], Item::leggings_ruby);ADD_OBJECT(map[4], Item::boots_ruby);Also update ArmorRecipes::GetArmorType() so quick-equip works:
case Item::helmet_ruby_Id: return eArmorType_Helmet;case Item::chestplate_ruby_Id: return eArmorType_Chestplate;case Item::leggings_ruby_Id: return eArmorType_Leggings;case Item::boots_ruby_Id: return eArmorType_Boots;Storage block recipe
Section titled “Storage block recipe”In OreRecipies.h, bump the max:
#define MAX_ORE_RECIPES 6 // was 5In OreRecipies.cpp, inside OreRecipies::_init():
ADD_OBJECT(map[5], Tile::rubyBlock);ADD_OBJECT(map[5], new ItemInstance(Item::ruby, 9));This registers both directions automatically: 9 rubies in a 3x3 makes 1 block, and 1 block in the grid makes 9 rubies.
Smelting recipe
Section titled “Smelting recipe”In FurnaceRecipes.cpp, inside the constructor:
addFurnaceRecipy(Tile::rubyOre_Id, new ItemInstance(Item::ruby), 1.0f);The third arg is the XP reward. Vanilla uses 0.7f for iron, 1.0f for gold/diamond. This recipe mainly matters for silk-touched ore.
9. World generation
Section titled “9. World generation”Ore generation happens in BiomeDecorator. The game uses OreFeature to place veins of a specific tile in stone underground.
How it works
Section titled “How it works”OreFeature(tileId, veinSize) creates a feature that replaces stone with your ore in blob-shaped clusters. The decorator then calls one of two placement methods:
decorateDepthSpan(count, feature, yMin, yMax) picks a random Y uniformly between yMin and yMax. Most ores use this.
decorateDepthAverage(count, feature, yCenter, ySpread) uses a triangular distribution centered on yCenter. Lapis uses this for a bell-curve effect.
Vanilla ore generation for reference:
| Ore | Vein Size | Veins/Chunk | Y Range | Method |
|---|---|---|---|---|
| Coal | 16 | 20 | 0-128 | depthSpan |
| Iron | 8 | 20 | 0-64 | depthSpan |
| Gold | 8 | 2 | 0-32 | depthSpan |
| Redstone | 7 | 8 | 0-16 | depthSpan |
| Diamond | 7 | 1 | 0-16 | depthSpan |
| Lapis | 6 | 1 | ~16 center | depthAverage |
Height values derive from Level::genDepth (128). So /2 = 64, /4 = 32, /8 = 16.
BiomeDecorator.h
Section titled “BiomeDecorator.h”Add the feature pointer in the protected section:
Feature *rubyOreFeature;BiomeDecorator.cpp
Section titled “BiomeDecorator.cpp”Inside _init():
rubyOreFeature = new OreFeature(Tile::rubyOre_Id, 4);Vein size 4 means small clusters. Diamond uses 7 for comparison.
Inside decorateOres(), before level->setInstaTick(false):
decorateDepthSpan(1, rubyOreFeature, 0, Level::genDepth / 8);That is 1 vein attempt per chunk, from Y=0 to Y=16. Small veins, low generation rate, deep underground only. Rubies will be rare. Bump the first arg (vein count) or the Y range to make them more common.
For more on custom generation including biome-specific spawning, see Custom World Generation.
10. Textures
Section titled “10. Textures”Every setTextureName() call maps to a real texture file. You need to provide all of these.
Block textures (terrain atlas)
Section titled “Block textures (terrain atlas)”| Texture name | Description |
|---|---|
oreRuby | Ruby ore block face |
blockRuby | Ruby storage block face |
Item textures (items atlas)
Section titled “Item textures (items atlas)”| Texture name | Description |
|---|---|
ruby | Ruby gem icon |
swordRuby | Ruby sword icon |
shovelRuby | Ruby shovel icon |
pickaxeRuby | Ruby pickaxe icon |
hatchetRuby | Ruby axe icon |
hoeRuby | Ruby hoe icon |
helmetRuby | Ruby helmet icon |
chestplateRuby | Ruby chestplate icon |
leggingsRuby | Ruby leggings icon |
bootsRuby | Ruby boots icon |
Armor model textures
Section titled “Armor model textures”Armor also needs two model layer images that render on the player body. Layer 1 covers helmet, chestplate, and boots. Layer 2 covers leggings. The render index 5 we used in the ArmorItem constructors tells the renderer which layer files to look for.
See Block Textures and Texture Packs for atlas file paths and format details.
11. String table entries
Section titled “11. String table entries”Every setDescriptionId() and setUseDescriptionId() references a string constant. Add all of these to your string table header:
IDS_TILE_RUBY_ORE / IDS_DESC_RUBY_OREIDS_TILE_RUBY_BLOCK / IDS_DESC_RUBY_BLOCKIDS_ITEM_RUBY / IDS_DESC_RUBYIDS_ITEM_SWORD_RUBYIDS_ITEM_SHOVEL_RUBYIDS_ITEM_PICKAXE_RUBYIDS_ITEM_HATCHET_RUBYIDS_ITEM_HOE_RUBYIDS_ITEM_HELMET_RUBY / IDS_DESC_HELMET_RUBYIDS_ITEM_CHESTPLATE_RUBY / IDS_DESC_CHESTPLATE_RUBYIDS_ITEM_LEGGINGS_RUBY / IDS_DESC_LEGGINGS_RUBYIDS_ITEM_BOOTS_RUBY / IDS_DESC_BOOTS_RUBYTool description IDs (IDS_DESC_SWORD, IDS_DESC_PICKAXE, etc.) are reused from vanilla since the description text is the same for every material.
12. Build system
Section titled “12. Build system”Add your new source files to cmake/Sources.cmake under MINECRAFT_WORLD_SOURCES:
Minecraft.World/RubyOreTile.hMinecraft.World/RubyOreTile.cppFile checklist
Section titled “File checklist”Here is every file this template touches, in order:
| File | Change |
|---|---|
Minecraft.World/RubyOreTile.h | New file |
Minecraft.World/RubyOreTile.cpp | New file |
Minecraft.World/Tile.h | Add rubyOre, rubyBlock pointers + IDs |
Minecraft.World/Tile.cpp | Static defs, const int defs, staticCtor() registration |
Minecraft.World/Item.h | Add gem, tools, armor pointers + IDs, _Tier::RUBY |
Minecraft.World/Item.cpp | Static defs, _Tier::RUBY def, staticCtor() registration, getTierItemId() |
Minecraft.World/ArmorItem.h | Add _ArmorMaterial::RUBY + rubyArray |
Minecraft.World/ArmorItem.cpp | Define armor material, update getTierItemId() |
Minecraft.World/ToolRecipies.cpp | Add ruby to tool recipe arrays |
Minecraft.World/WeaponRecipies.cpp | Add ruby to weapon recipe arrays |
Minecraft.World/ArmorRecipes.cpp | Add ruby to armor arrays + GetArmorType() |
Minecraft.World/OreRecipies.h | Bump MAX_ORE_RECIPES to 6 |
Minecraft.World/OreRecipies.cpp | Add ruby block recipe |
Minecraft.World/FurnaceRecipes.cpp | Add ruby ore smelting |
Minecraft.World/BiomeDecorator.h | Add rubyOreFeature pointer |
Minecraft.World/BiomeDecorator.cpp | Create feature, add to decorateOres() |
cmake/Sources.cmake | Add new source files |
Testing your mod
Section titled “Testing your mod”Build and load a new world. Verify all of these work:
- Ruby ore spawns below Y=16
- Mining it drops rubies and XP orbs (3-7 XP)
- Fortune increases ruby drops
- Silk Touch drops the ore block itself
- Ruby ore smelts into a ruby in the furnace
- 9 rubies craft into a ruby block and back
- All 5 tools craft correctly at a workbench
- All 4 armor pieces craft correctly
- Tools and armor can be repaired with rubies on an anvil
- Tool durability, speed, and damage feel right
If nothing spawns, double-check that you made a new world. Existing chunks will not have ruby ore.
Making it your own
Section titled “Making it your own”To turn this into a different material (sapphire, amethyst, titanium, whatever):
- Find-and-replace
Ruby/rubywith your material name - Pick new unused IDs in the same ranges
- Adjust the tier numbers (
_Tierconstructor) for your desired balance - Adjust the armor material numbers for protection and durability
- Change the XP range in
spawnResources()if you want - Change vein size and Y range in
BiomeDecoratorfor rarity - Create your own textures
- Update all string table entries
The structure stays identical. Only the names and numbers change.
Related docs
Section titled “Related docs”- Adding Blocks
- Adding Items
- Adding Recipes
- Custom World Generation
- Block Textures
- Texture Packs
- Full Ore Guide (longer version with more background)