Scripting Expressions - MehVahdJukaar/polytone GitHub Wiki

Scripting Expressions

Many of the mod systems can be customized with Expression values, allowing for arbitrary dynamic queries of game parameters. This system is VERY powerful but at the same time it's an avanced concept.

Scripting Expressions are a 1.21.11+ concept (for now) which replace the old Math Expressions.

Struggling with scripting? Fret not, AI is just right for tasks like this, you can try to copy this wiki and the relevant Modifiers sections (i.e. particle modifiers) into an AI Chatbot and ask it what to write.

Introduction

This system is powered by the MVEL library, a Java scripting library which allows to create expressive scripting-like curly braced styled expressions. These will have a syntax very similar to other curly brackets scripting languages such as JavaScript and allow you to have things such as dynamic method invocations, local variable declarations, if statements and multiple line statements.

Example

Here is an example that uses the expression system to do something complex:

NOTE that this wiki page has new lines characters JUST for visibility sake. You have to REMOVE them for it to be valid json syntax unfortunately.

{
 "some_expression_in_modifiers": "

    t = global.getTime();

    r = 0.5;
    g = 0.5;
    b = 0.5;

    if (player.speed() > 0.3) {
        r = 1.0;
    } else if (player.speed > 0.1) {
        r = 0.7;
    }

    if (object.canSeeSky()) { 
        g = clamp(object.skyLight / 15, 0, 1);
    } else {
        g = 0.2;
    }

    if (t % 2 < 1) {
        b = 0.5 + 0.5 * sin(t);     
    } else {
        b = 0.3 + 0.3 * cos(global.time()); 
    }

    if (p.inWater) {            
        g += 0.2;                     
    }

    color(r, g, b, 1.0);
}
"
}

Context Functions

Expression scripting exposes a number of context object, each varying depending on the current expression that you are using. Each object can be accessed with the . operator to invoke one of its functions. Here is an example invoking the getArmor function on the player context object and returns 1 if the helmet is iron helmet.

player.getArmor('head') == 'minecraft:iron_helmet' ? 1 : 0

Each function can either be called with its name (with or without brachets if it has no arguments) or with its getter. Example for age, some of the valid syntaxes are.

  • player.age
  • p.getAge()
  • player.age()

Contexts Availability

Block Modifiers & Colormap Expressions:

  • object: Positional Context
  • player: Player Context
  • camera: Camera Context
  • global: Global Context
  • random: Random Context

Particle Modifiers Expressions:

  • object: Particle Context
  • player: Player Context
  • camera: Camera Context
  • global: Global Context
  • random: Random Context

Variant Animated Textures & Global Expressions Expressions:

  • player: Player Context
  • camera: Camera Context
  • global: Global Context
  • random: Random Context

Entity Modifiers Expressions:

  • object: Entity Context
  • player: Entity Context
  • camera: Camera Context
  • global: Global Context
  • random: Random Context

Global Context

This one can be accessed with global or g. Available on all expressions.

Method / Field Return Type Description / Notes
time() double Current game time in ticks
dayTime() double Current day time in ticks
season() String Current season name, if a season mod is present
seasonNumber() double Current season number. 0-1
skyType() int
dimensionType() String Name of current dimension
rain() double Current rain + thunder value. 0-1
environmentAttribute(attributeName: String) String - number Value of a global named environment attribute

Positional Context

This one is shared between Player Object, Particle Object, Camera Object and more. It's also found alone in Colormap Expressions or Block Modifiers under the name object or o Its simply reported here for brevity not to duplicate its content into each of those sections below. The section itself contains a lot of functions that query the world for attributes that are relevant at a particular block position.

Method Return Type Description / Notes
x() double Object X position
y() double Object Y position
z() double Object Z position
block() String Registered name of the block at the current position
blockState() String Full string representation of the block state
blockStateValue(input: Object) String / number Value of a specific block state property
biome() String Name of the biome at the current position
biomeIndex() double Legacy biome mapper
biomeIndex(biomeMapper: String) double Biome index using a specific mapper
temperature() double Climate temperature of the biome
downfall() double Climate rainfall of the biome
skyLight() int Sky light level at the current position position
blockLight() int Block light level at the current position position
canSeeSky() boolean True if the position can see the sky
hasEntitiesWithin() boolean True if any entities intersect the object's bounds
hasBlockTag(tag: String) boolean True if the block matches the given tag
hasAirAt() boolean True if the position is air
hasFluid() boolean True if the positon contains fluid
fluid() String Name of the fluid at the current position
hasBlockEntity() boolean True if the position has a block entity
blockEntity() String Name of the block entity, or "null"
environmentAttribute(attributeName: String) String - number Value of a named environment attribute at the current position

Entity Context

This type is used for Entity Context, called objector o, just available in Entity Modifiers Expressions. Here is its complete API. The functions from Positional Context are also included in this but wont be reported below.

Function Return Type Description / Notes
xd() double Player X velocity
yd() double Player Y velocity
zd() double Player Z velocity
inWater() boolean True if player is in water
swimming() boolean True if player is swimming
flying() boolean True if player is fall flying
crouching() boolean True if player is crouching
sleeping() boolean True if player is sleeping
onGround() boolean True if player is on the ground
health() double Current player health
maxHealth() double Maximum player health
hurtTime() double Time since last damage
age() int Player tick count (age)
speed() double Player movement speed
speedSq() double Player movement speed squared. Faster than calling speed
walkAnimation() double Walk animation position
walkAnimationSpeed() double Walk animation speed
mainHandItem() String Registered name of main hand item
offHandItem() String Registered name of offhand item
armor(slot: String) String Registered name of armor in the given slot (feet, legs, chest, head)
height() double Bounding box height
width() double Bounding box width
eyeHeight() double eye height
owner() Entity Context / null Another entity context of the entity that owns this entity, used for pets and projectiles. Can be null so you must check for that

Player Context

Called player or shorthand p; available in every expression type.

It can use EVERYTHING described in Entity Context PLUS these:

Function Return Type Description / Notes
itemUsedTicks() int Item use ticks
itemUsed() string Item used

Particle Context

This one is used in Particle Modifiers or Custom particles. You will be able to reference it with they keyworld object or o. The functions from Positional Context are also included in this but wont be reported below. Here is its complete API.

Method / Field Return Type Description / Notes
xd() double Particle X velocity
yd() double Particle Y velocity
zd() double Particle Z velocity
red() double Red color component (1.0 if not a quad particle)
green() double Green color component (1.0 if not a quad particle)
blue() double Blue color component (1.0 if not a quad particle)
alpha() double Alpha transparency (1.0 if not a quad particle)
roll() double Particle roll (0.0 if not a quad particle)
size() double Particle size (default 0.15F if not a quad particle)
age() int Current particle age
life() int Total particle lifetime
color() int rgb color
custom() double Particle Custom variable. You just have 1 of these

ADVANCED:

Particle context also allows to SET values directly. This is useful as it allows you to run LESS expressions per particle and hence will have a performance boost. The syntax for this is simple as the variable names are the same as the getters above but can be prefixed by a set keyword. Additionally the setRemoved / removed and setColorFrom(colormapName: String) / colorFrom(colormapName: String) functions are available. Additionally these can be used in a ticker or initializer(not supported yet) custom particle object without the need to have nested expressions, the ticker itself WILL BE an expression that does everything.

This MIGHT or MIGHT NOT improve performance.

{
  "ticker": "
     if(o.age>4){
       o.setRemoved();
     };
     o.roll = 2 + o.roll;
     o.alpha = 0.4;
     o.setBlue(255);
     o.setColor(colormap
  "
}

Camera Context

This one can be accessed with camera or c in all expressions. It includes all the functions from Positional Context.

Method / Field Return Type Description / Notes
yaw() double Camera yaw rotation
pitch() double Camera pitch rotation
roll() double Camera roll rotation
detatched() boolean True if camera is detached
viewDistance() int Current render distance from game options
fov() double Fov angle in degrees
lookingToward(x: double, y: double, z: double) Helper function that checks if a position is infront of the camera and within its FOV

Random Context

Contrary to math functions, radom math functions are accessed by a random or r object. This is done since random invocations could be seeded and deterministic and hence isnt a global property. For instance a random call in a block colormap will always result in the same value at a particular position. Accessible in all expressions.

Method / Field Return Type Description / Notes
randInt() int Returns a random integer
randInt(bound: int) int Returns a random integer between 0 (inclusive) and bound (exclusive)
randInt(origin: int, bound: int) int Returns a random integer between origin (inclusive) and bound (exclusive)
rand() double Returns a random double between 0.0 and 1.0
rand(bound: double) double Returns a random double between 0.0 and bound
rand(origin: double, bound: double) double Returns a random double between origin and bound
gaussian() double Returns a random number following standard Gaussian distribution
gaussian(mean: double, deviation: double) double Returns a random Gaussian with given mean and standard deviation
noise(name: String, x: double, y: double) double Returns the value of a registered noiseat (x, y). See the end of the Math Expression section
noise(x: double, y: double) double Returns the value of the default Perlin simplex noise at (x, y)

Math Functions

These dont need a context and can be called directly. Also listed are some constant values you can use.

Method / Field Return Type Description / Notes
PI double Constant π
TAU double Constant 2π
E double Constant e
PSI double Golden ratio
sin(x: double) double Sine of x (radians)
cos(x: double) double Cosine of x (radians)
tan(x: double) double Tangent of x (radians)
atan2(y: double, x: double) double Arc tangent of y/x
sqrt(x: double) double Square root of x
abs(x: double) double Absolute value of x
log(x: double) double Natural logarithm of x
exp(x: double) double Exponential e^x
pow(a: double, b: double) double a raised to the power of b
floor(x: double) double Largest integer ≤ x
ceil(x: double) double Smallest integer ≥ x
round(x: double) double Closest integer to x
fract(x: double) double Fractional part of x
sign(x: double) double Sign of x (-1, 0, 1)
radians(degrees: double) double Convert degrees to radians
degrees(radians: double) double Convert radians to degrees
mod(x: double, y: double) double Positive modulo of x by y
min(a: double, b: double) double Minimum of a and b
max(a: double, b: double) double Maximum of a and b
clamp(val: double, min: double, max: double) double Clamp val between min and max
square(x: double) double x squared
cube(x: double) double x cubed
lerp(a: double, b: double, t: double) double Linear interpolation between a and b
inverseLerp(a: double, b: double, v: double) double Normalized position of v between a and b
smoothstep(edge0: double, edge1: double, x: double) double Smoothstep interpolation between edges
distSquare(x1: double, y1: double, x2: double, y2: double) double Squared distance between two points
distSquare(p1: Vec3i, p2: Vec3i) double Squared distance between two Vec3i points
dist(x1: double, y1: double, x2: double, y2: double) double Distance between two points
dist(p1: Vec3i, p2: Vec3i) double Distance between two Vec3i points
red(color: double) double Red component of ARGB color (0–1)
green(color: double) double Green component of ARGB color (0–1)
blue(color: double) double Blue component of ARGB color (0–1)
alpha(color: double) double Alpha component of ARGB color (0–1)
color(r: double, g: double, b: double, a: double) int Packs RGBA floats into ARGB int

Global Functions

These are accessible anywhere just like math ones

Method / Field Return Type Description / Notes
colormap(colormapName: String, ?x: int, ?y: int, ?z: int, ?tintIndex: int) int Samples a custom colormap at the specific position and with the specific tint index provided. Last 4 parameters are optional
config(configId : string) string / number Config value of the custom Polytone Config
modOn(modId : string, ?modVersionrange : string) boolean Rerturns if a mod is loaded. Version range is optional. Can be single version or range
dateYear() int Current system year
dateMonth() int Current system month
dateDay() int Current system day
dateHour() int Current system hour
dateMinute() int Current system minute
dateTime() int Current system time
dateDayOfTheYear() int Current system day of year
modLoader() string Current Mod Loader. Can be Fabric or Neoforge

Global Expressions

This is an advanced concept that allows you to run certain expressions every tick to set certain global variables that you can then reference in your Script Expressions.

To do so you'll have to place json files in the global_expressions folder. Syntax is very simple and fields are as in the following example.

{
  "update_interval": 1,
  "default_value": 0,
  "expression": "g.time + p.age/2 + g.rain"
}

Given the name of the json file, a variable with the name [file namespace]_[file name] will be assigned every update_interval ticks according to your expression. You can then reference it in your other Scripting Expressions. For instance imagine your pack namespace is my_pack and the json file is called some_calculation, then you can reference it like such:

{
 "some_example_expression_field": "sin(my_pack_some_calculation + 3) /2.0)"

}

Disclaimer

All credits to MVEL library which powers this system.

If you need more functions addded to the API contact me.