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:

  • GlobalsonEvent, 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