Skip to main content

Getting Started with Atomicoffe

Atomicoffe is a Fabric mod for Minecraft 1.21.11 that lets you write server and client-side logic in Lua without compiling Java. Drop .lua files into a folder, reload, and your changes are live.


Requirements​

RequirementVersion
Minecraft1.21.11
Fabric Loader0.18.4+
Fabric API0.141.3+1.21.11+
Java21+

Installation​

  1. Install Fabric Loader for Minecraft 1.21.11.
  2. Drop Fabric API and atomicoffe into your mods/ folder.
  3. Launch the game once — Atomicoffe will create its script directories automatically.

Script Directories​

After the first launch, open your game directory (.minecraft/ or your server root). You will find:

<gameDir>/
└── atomicoffe/
├── startup_scripts/ ← runs at mod init (registration)
├── server_scripts/ ← runs when a server/world starts
├── client_scripts/ ← runs on the client only
├── playerdata/ ← auto-managed per-player JSON storage
├── config.json ← mod config (managed by the config API)
└── data/ ← generated tag files (managed by the Tags API)

Every .lua file inside a phase directory is loaded automatically in alphabetical order.


Your First Script​

Create the file atomicoffe/server_scripts/hello.lua:

-- Greet players when they join
onEvent("player.join", function(e)
e.player.tell("§aWelcome to the server, §e" .. e.player.name .. "§a!")
server.broadcast("§b" .. e.player.name .. " §fhas joined the game.")
end)

-- Register a simple command
command.register("ping", function(ctx)
ctx.reply("Pong! The server has " .. server.getPlayerCount() .. " player(s) online.")
end)

Start your server (or open a singleplayer world). When a player joins, they'll be greeted, and /ping will be available to everyone.


Reloading Scripts​

You never need to restart the server to apply changes.

ActionEffect
/atomicoffe reloadRe-runs all server_scripts/
F3+TRe-runs all client_scripts/ (resource pack reload)
/reloadFull data-pack reload (re-applies recipes, tags, loot)

Event System​

Everything in Atomicoffe is driven by events. Use onEvent(id, fn) to subscribe:

onEvent("player.death", function(e)
-- e.player — the player who died
-- e.damage — damage amount
-- e.source — damage source ID string
server.broadcast(e.player.name .. " died! (" .. e.source .. ")")
end)

Full Event Reference​

Player Events​

Event IDPhaseContext Fields
player.joinServerplayer
player.logged_inServerplayer (alias for player.join)
player.leaveServerplayer
player.logged_outServerplayer (alias for player.leave)
player.deathServerplayer, damage, source
player.respawnServerplayer, alive
player.chatServerplayer, message
player.tickServerplayer (fires every tick — be careful!)
player.break_blockServerplayer, block, pos {x,y,z}

Block Events​

Event IDPhaseContext FieldsCancellable
block.right_clickedServerplayer, block, pos, hand, face, sneaking, item, itemStack, hitPosYes
block.sneak_right_clickedServerSame as aboveYes
block.left_clickedServerplayer, block, pos, hand, face, sneaking, item, itemStackYes
block.sneak_left_clickedServerSame as aboveYes

Item Events​

Event IDPhaseContext FieldsCancellable
item.usedServerplayer, hand, sneaking, item, itemStackYes
item.sneak_usedServerSame as aboveYes

Entity Events​

Event IDPhaseContext FieldsCancellable
entity.spawnedServerentity
entity.killedServerkiller, killed, player (if player killed)
entity.hurtServerentity, damage, source, attacker, directSource, projectile, isExplosion, isFire, isProjectileYes
entity.deathServerSame as entity.hurtYes

Server / World Events​

Event IDPhaseContext Fields
server.startedServer—
server.stoppingServer—
server.tickServer— (fires every tick)
level.loadedServerdimension
level.unloadedServerdimension
level.tickServerdimension (fires every tick per dimension)

Data Events (Startup Phase)​

Event IDPhaseContext
item.registryStartupItem registration context
block.registryStartupBlock registration context
fluid.registryStartupFluid registration context
mob_effect.registryStartupMobEffectRegistry context
creative_tab.registryStartupCreative tab context
recipesServerRecipe context
loot.modifyServertableId, addDrop(itemId, count)
Cancellable events

Return false from a handler registered for a cancellable event to prevent the default action.

onEvent("entity.hurt", function(e)
-- Make all players immune to fire
if e.isFire and e.entity.type == "minecraft:player" then
return false -- cancel the damage
end
end)

Script Examples​

Give a diamond on first join​

-- server_scripts/welcome.lua

onEvent("player.join", function(e)
local p = e.player
if not data.has(p.uuid, "welcomed") then
data.set(p.uuid, "welcomed", true)
p.give("minecraft:diamond", 1)
p.sendTitle("§6Welcome!", "§eHere's a diamond to start.", 10, 70, 20)
end
end)

Kill counter scoreboard​

-- server_scripts/kills.lua

scoreboard.createObjective("kills", "Player Kills")

onEvent("entity.killed", function(e)
if e.player then
local newKills = scoreboard.add(e.player.name, "kills", 1)
e.player.sendActionBar("§cKills: §f" .. newKills)
end
end)

Custom recipe​

-- server_scripts/recipes.lua

onEvent("recipes", function(e)
-- 4 diamonds from a diamond block
e.addShaped("mymod:diamonds_from_block", "minecraft:diamond 4",
{"X"},
{ X = "minecraft:diamond_block" }
)

-- Remove the default creeper-face banner pattern recipe
e.remove({ id = "minecraft:creeper_banner_pattern" })
end)

Repeating announcement​

-- server_scripts/announcements.lua

local messages = {
"§bRemember to vote!",
"§aDiscord: discord.gg/example",
"§eRules: /rules",
}
local index = 1

-- Announce every 5 minutes (6000 ticks)
schedule.every(6000, function()
server.broadcast(messages[index])
index = (index % #messages) + 1
end)

Client HUD​

-- client_scripts/hud.lua

client.onHudRender(function(e)
local p = client.getPlayer()
if not p then return end

-- Dark bar at top-left
e.drawRect(2, 2, 120, 12, 0x88000000)
e.drawText("Pos: " .. math.floor(p.x) .. " " .. math.floor(p.y) .. " " .. math.floor(p.z), 4, 4, 0xFFFF55)
end)

API Reference​

Explore the full API documentation:

  • Globals — onEvent, print, logger
  • server — players, broadcast, TPS, weather
  • world — blocks, entities, particles, time
  • Player Context — health, inventory, effects, messages
  • command — custom slash commands
  • schedule — tick-based timers
  • network — custom client↔server packets
  • scoreboard — objectives and scores
  • data — persistent per-player storage
  • config — shared mod config
  • Recipes — add/remove crafting recipes
  • loot — modify loot tables
  • Tags — modify data-pack tags
  • MobEffectRegistry — register status effects
  • client — HUD, keybinds, client networking