Skip to content

Loops and Functions

For: advanced users repeating work.

<for> and <while> loops plus run-local <def> functions. The one-line forms live in the cheatsheet.

Loops

Tag Meaning
<for:list,body> Run the body per item with the item behind <i>; text the body produces is discarded.
<while:cond,body> Repeat the body while the condition holds.
<i> Innermost for-loop item, else null.

<for:list,body> walks a list with each item behind <i>, and <while:condition,body> repeats while its condition holds. Bodies run for side effects (flag writes, messages, sounds, <run> commands) and any text they produce is discarded; both loops leave nothing behind on success. Like <if>, loops see flag writes earlier on the line (see Conditions):

- '<gflag:out,[]>'
- '<for:<range:3>,<list.append:<gflag:out>,item<i>>>'
- 'say <gflag:out>'
- '<for:<active-players:HUNTER>,<run:effect give <i> minecraft:glowing 10>>'

This says [item0, item1, item2], then gives every hunter ten seconds of glowing: <run:> dispatches its evaluated body from the console per iteration, with the blacklist enforced and exit holding no special meaning inside it.

This says [item0, item1, item2]. Nested loops work, with <i> always reading the innermost item; outside any for loop <i> is a silent null. The while condition re-resolves every iteration and accepts a bare true/false word or a full condition (<gflag:n> lt 3); anything else warns and the whole tag becomes null.

Two tripwires keep loops honest. A for loop over a flag reference snapshots the flag and cancels to null with a warning when the body changes it mid-loop (literals cannot change, so they never cancel). And every line gets 20000 shared steps, split between loop iterations and function calls: past that the tag becomes null, the match is cancelled, the console logs JMHScript loop exceeded 20000 steps at plus the modifier, behavior, list, and line, and the players are told to contact the administrator. A line that overflows the stack before the budget trips cancels the same way but logs JMHScript stack exhausted evaluating instead, so the two failures are easy to tell apart. Escape literal < and > inside loop bodies (see Escaping Special Characters): quotes never hid tags from the scanner.

Functions

Tag Meaning
<def:name,body,params...> Run-local function; the body stores verbatim until called.
<run:command> Run a console command, empty (exit holds no special meaning inside).
<runblock:id,args...> Run a behavior block of this modifier, empty; extra parts rebind <args:N> inside.

<def:name,body,params...> defines a run-local function; the body stores verbatim and never evaluates at definition time. Calling <name:args...> substitutes each param with its arg, then evaluates the body like any command line, so calls nest and recurse:

- '<def:double,x+x,x>'
- 'say <double:21>'
- '<def:countdown,<if:n le 0,done,<countdown:n-1>>,n>'
- 'say <countdown:3>'

This says 42, then done. Names are case-insensitive, use letters, digits, and _, and must not collide with builtin tags (redefining one warns and is ignored). All params are optional: missing args bind null with no warning, while extra args warn and are ignored. Params substitute as bare case-sensitive tokens outside quotes, in one pass, so an arg holding a param name is never re-substituted; quoted text is left alone. Like every tag, substitution is textual: math bodies should parenthesize params ((B)**2 rather than B**2) so negative args bind as one value, and bare math still needs no-space runs. Definitions live and die with the run like <lflag>. The creator editor collects every <def:name> in the edited line's function scope, so calls to defined functions (including recursive self-calls and calls from other lines in the same scope) never warn; genuinely unknown tags still warn, and still resolve at runtime.

Recursion terminates through <if> base cases, since dead branches never run. Every call costs one of the line's 20000 shared steps, and the budget never refunds: leaving a loop cannot launder steps back, so runaway recursion always ends at the limit above instead of crashing the server.

Next Steps