Skip to content

Value types and coercion

Type table

Kind Java type Literal typeName()
number Double (double primitive when inferred) 3, 7.5 "number"
text String "hi" "text"
boolean Boolean (boolean when inferred) true "boolean"
list ArrayList none (build via list()/split) "list"
map Map none "map"
player Bukkit Player none (via player()/sender()) class name
null null null "null"

toNumber(x)

Number as-is; Boolean → 1/0; String gets parsed (empty/garbage is EvalException: cannot use ... as a number); anything else is the same error. null is an error — initialize your counters!

toBool(x)

Boolean as-is; number is != 0; text is non-empty and not "false" (case-insensitive: "False" is false too); null → false; everything else (lists, players) → true.

if "false":     # does NOT run
    message "x"
if "anything":  # runs
    message "y"

toText(x)

null → "" (empty, not "null"!); integral doubles without .0 (5, not 5.0); lists as [a, b]; the rest via String.valueOf.

message "Balance: " + #coins   # numbers render nicely
message "Nick: " + victim      # a player object renders as toString(), NOT the nick! use name(victim)

Player objects in text

Concatenating a player object yields CraftPlayer{...}, not the nickname. The nick comes only from name(p) / sender-name() / p.name.

Equality looseEquals

Both null → true; one null → false; two numbers by value (3 == 3.0 → true); a string on either side compares texts (5 == "5" → true); otherwise Objects.equals.

for over a non-list is an empty loop

Values.toList returns a copy of a list, and for anything else — an empty list with no error. for x in 42: simply runs zero iterations. Typos in the loop source stay silent — double-check them visually.