Skip to content

Templates

Copy-paste-ready templates for everything EpochStages can do. Every code block has a copy button (top-right corner).

  • JSON ruleskubejs/data/<namespace>/<dir>/<name>.json (any namespace; apply with /reload).
  • Scriptskubejs/server_scripts/*.js.

Need the details?

Field-by-field reference is in the KubeJS & Datapack guide.


1. Full 10-age starter

Declare a whole progression in one script. Each age requires the previous, so /epochstages grant enforces the order. Players begin in the Dark Age (granted on first join).

// kubejs/server_scripts/ages.js
StageEvents.register(event => {
  event.add('dark_age', 'Dark Age')
  event.add('medieval', 'Medieval')
  event.add('renaissance', 'Renaissance')
  event.add('age_of_exploration', 'Age of Exploration')
  event.add('industrial_revolution', 'Industrial Revolution')
  event.add('gilded_era', 'Gilded Era')
  event.add('atomic_age', 'Atomic Age')
  event.add('information_age', 'Information Age')
  event.add('otherworldly', 'Otherworldly')
  event.add('ascension', 'Ascension')
})

// Everyone starts in the Dark Age
PlayerEvents.logged_in(event => {
  if (!Stages.has(event.player, 'dark_age')) {
    Stages.grant(event.player, 'dark_age')
  }
})

2. Stage definition (JSON alternative)

kubejs/data/<ns>/epoch_stages/medieval.jsonthe file name is the stage id. Use this or the script above, not both.

{
  "display_name": "<Display Name>",
  "sort_index": 0,
  "description": "<shown in tooltips / catalog>",
  "requires": ["<prerequisite_stage_id>"]
}
{
  "display_name": "Medieval",
  "sort_index": 2,
  "description": "Iron, early magic, medieval life.",
  "requires": ["dark_age"]
}

3. Lock a whole mod

kubejs/data/<ns>/epoch_mod_stages/<name>.json — locks every item / recipe / mob of the listed mods until the stage. mods is a list of namespaces.

{
  "stage": "<stage_id>",
  "mods": ["<modid>", "<modid2>"],
  "except_items": ["<token to keep available>"],
  "except_recipes": [],
  "message": "<shown when blocked>"
}
{
  "stage": "industrial_revolution",
  "mods": ["create", "mekanism"],
  "except_items": ["*:*book*", "*:*guide*"],
  "except_recipes": [],
  "message": "Locked until the Industrial Revolution."
}

except_items / except_recipes are matcher tokens (see the table below) that stay available even though the mod is locked — handy for pulling one starter recipe out of an otherwise-hidden mod.


4. Ore remap

kubejs/data/<ns>/epoch_ore_remaps/<name>.json — while the stage is locked, the ore block is swapped (reversibly, server-side) to the substitute, so Jade / JEI / other mods all see the substitute too.

{
  "stage": "<stage_id>",
  "ores": ["#c:ores/<material>", "<modid>:<ore>"],
  "substitute_block": "minecraft:coal_ore",
  "substitute_drop": "minecraft:coal"
}
{
  "stage": "medieval",
  "ores": ["#c:ores/iron", "minecraft:iron_ore", "minecraft:deepslate_iron_ore"],
  "substitute_block": "minecraft:coal_ore",
  "substitute_drop": "minecraft:coal"
}
{
  "stage": "ascension",
  "ores": ["*:*_ore", "*:*_ore_*"],
  "substitute_block": "minecraft:coal_ore",
  "substitute_drop": "minecraft:coal"
}

Specific rules beat broad ones automatically (exact > tag > wildcard), so the catch-all hides unknown ores while iron keeps its own stage. coal_ore / deepslate_coal_ore are never remapped.


5. Gate items / recipes / mobs / dimensions

kubejs/data/<ns>/epoch_gates/<name>.json — piecemeal gating. Every category is optional.

{
  "stage": "<stage_id>",
  "message": "<shown when blocked>",
  "items": ["<token>"],
  "recipes": ["<recipe id>"],
  "mobs": ["<entity token>"],
  "dimensions": ["<dimension id>"]
}
{
  "stage": "age_of_exploration",
  "message": "You can't enter the Nether yet.",
  "items": ["minecraft:flint_and_steel"],
  "recipes": [],
  "mobs": [],
  "dimensions": ["minecraft:the_nether"]
}

Matcher tokens

Used by items / recipes / mobs / dimensions / ores (and the except_* lists):

Form Example Matches
exact minecraft:iron_pickaxe exactly that id
wildcard create:* * = any run, over the full namespace:path
tag #c:ingots/iron everything in the tag

In epoch_mod_stages, mods is plain namespaces (create), not tokens.


6. KubeJS — grant stages dynamically

kubejs/server_scripts/progression.js

PlayerEvents.advancement(event => {
  if (event.advancement.id == 'minecraft:story/smelt_iron') {
    Stages.grant(event.player, 'medieval')
    event.player.tell('You have entered the Medieval age!')
  }
})
PlayerEvents.inventoryChanged(event => {
  if (event.item.id == 'allthemodium:allthemodium_ingot' && !Stages.has(event.player, 'ascension')) {
    Stages.grant(event.player, 'ascension')
  }
})
// The unlock: system is driven by the command; run it as the server:
event.player.server.runCommandSilent(`epochstages unlock ${event.player.username} minecraft:iron_ore`)

Queries: Stages.has(player, id), Stages.of(player), Stages.revoke(player, id), Stages.defined().


7. Tie stages to FTB Quests

The simplest path — no scripting. Give the quest a Command reward:

/epochstages grant @s medieval
/epochstages unlock @s minecraft:iron_ore


8. Commands cheat-sheet (op level 2)

Command Effect
/epochstages grant <players> <stage> grant (respects prerequisites)
/epochstages force <players> <stage> grant, ignoring prerequisites
/epochstages revoke <players> <stage> remove a stage
/epochstages clear <players> remove all stages
/epochstages list <player> show the player's stages + unlocks
/epochstages unlock <players> <content> reveal one item / ore
/epochstages lock <players> <content> undo an unlock
/epochstages editor open the in-game editor

kubejs/
  server_scripts/
    ages.js            # declare stages + grant dark_age on join
    progression.js     # dynamic grants
  data/<yourpack>/
    epoch_stages/      # (optional) stage defs as JSON
    epoch_mod_stages/  # mod locks — one file per age
    epoch_ore_remaps/  # ore gating
    epoch_gates/       # item / recipe / mob / dimension gates