2.0.1 • Published 2 years ago

molang v2.0.1

Weekly downloads
90
License
MIT
Repository
github
Last release
2 years ago

Molang

A fast Molang parser used and developed by the bridge. team. This library has full support for all of Minecraft's Molang features.

About

Molang is a simple expression-based language designed for fast calculation of values at run-time. Its focus is solely to enable script-like capabilities in high-performance systems where JavaScript is not performant at scale. We need scripting capabilities in these low-level systems to support end-user modding capabilities, custom entities, rendering, and animations.

- From the Minecraft documentation

Installation

  • npm i molang

    or

  • Download the dist/main.web.js file and add the script to your HTML page (library access via global Molang object).

Basic Usage

To execute a basic Molang statement, first construct a new instance of the Molang class. The first constructor argument is the environment your Molang script will have access to and the second argument configures the Molang interpreter. Take a look at the IParserConfig interface for a list of all available options.

molang.execute(...) simply executes a Molang script and returns the value it evaluates to.

import { Molang } from 'molang'

const molang = new Molang(
	{
		query: {
			x: 0,
			get(val) {
				return val + 4
			},
		},
	},
	{ useCache: true }
)
molang.execute('query.x + query.get(3) == 7')

Setting up nested environments

For the context switching operator "->", you can set up nested environments like this:

import { Molang, Context } from 'molang'

const molang = new Molang({
	query: {
		test: 1,
	},
	context: {
		other: new Context({
			query: { test: 2 },
		}),
	},
})

molang.execute('query.test') // Returns 1
molang.execute('context.other->query.test') // Returns 2

Using Custom Molang Functions

Custom Molang functions were designed to support .molang files within bridge.

import { CustomMolang } from 'molang'

const customMolang = new CustomMolang({})

const molangFunctions = ... // Somehow load Molang input that defines custom functions

// Make custom functions known to Molang parser
customMolang.parse(molangFunctions)

const molangSource = ... // Somehow load Molang source from JSON files

const transformedSource = customMolang.transform(molangSource)
... // Write the transformed source string back to the JSON file or do further processing

A custom Molang function is defined like this:

function('sq', 'base', {
	return math.pow(a.base, 2);
});

function('pow', 'base', 'exp', {
	return a.exp == 0 ? 1 : a.base * f.pow(a.base, a.exp - 1);
});
  • The first argument always defines the function name
  • All following arguments except the last one define input arguments
  • The last argument is the function body
  • Temporary variables get scoped to the current function body automatically
  • Basic recursion is supported as long as the interpreter can stop the recursive calls at compile-time
  • To call a function inside of Molang scripts, simply do f.sq(2) or f.pow(3, 2)

Using AST Scripts

You can write abitrary scripts to traverse the abstract syntax tree this library builds.

import { Molang, expressions } from 'molang'

const molang = new Molang()

let ast = molang.parse(`context.other->query.something + 1`)
const { NumberExpression } = expressions

// This increments all numbers within a Molang script
ast = ast.walk((expr) => {
	if (expr instanceof NumberExpression)
		return new NumberExpression(expr.eval() + 1)
})

const output = ast.toString() // 'context.other->query.something+2'

Performance

Disclaimer: Both bridge.'s Molang library and Blockbench's library are usually fast enough. However, bridge.'s Molang interpreter shines when it comes to executing a wide variety of different scripts (ineffective cache) where it is up to 10x faster at interpreting a vanilla Molang script.

Vanilla Script

The following script gets executed 100,000 times for the first test:

variable.hand_bob = query.life_time < 0.01 ? 0.0 : variable.hand_bob + ((query.is_on_ground && query.is_alive ? math.clamp(math.sqrt(math.pow(query.position_delta(0), 2.0) + math.pow(query.position_delta(2), 2.0)), 0.0, 0.1) : 0.0) - variable.hand_bob) * 0.02;

Molang

Used by bridge.

TestAverage Time
Parse & Execute (uncached)1253.332ms
Parse & Execute (cached)90.036ms

MolangJS

Used by Blockbench & Snowstorm | Test | Average Time | | -------------------------- | ------------ | | Parse & Execute (uncached) | 11872ms | | Parse & Execute (cached) | 185.299ms |

Early Return

The same script as above, except that we now insert a "return 1;" in front of it. bridge.'s interpreter is smart enough to figure out that the whole expression is static after it parsed return 1;. These kinds of optimizations can be found throughout our library.

Molang

Used by bridge.

TestAverage Time
Parse & Execute (uncached)103.61ms
Parse & Execute (cached)8.835ms

MolangJS

Used by Blockbench & Snowstorm | Test | Average Time | | -------------------------- | ------------ | | Parse & Execute (uncached) | 13230.682ms | | Parse & Execute (cached) | 147.786ms |

Molang Playground

We have built a very basic Molang playground with this interpreter. You can use it at bridge-core.github.io/molang-playground.

2.0.1

2 years ago

2.0.0

2 years ago

1.13.11

2 years ago

1.13.10

2 years ago

1.13.6

2 years ago

1.13.9

2 years ago

1.13.8

2 years ago

1.13.7

2 years ago

1.13.5

2 years ago

1.13.4

2 years ago

1.13.3

3 years ago

1.13.2

3 years ago

1.13.1

3 years ago

1.12.3

3 years ago

1.13.0

3 years ago

1.12.2

3 years ago

1.12.1

3 years ago

1.12.0

3 years ago

1.11.3

3 years ago

1.11.2

3 years ago

1.11.1

3 years ago

1.11.0

3 years ago

1.10.0

3 years ago

1.9.1

3 years ago

1.9.0

3 years ago

1.8.1

3 years ago

1.8.0

3 years ago

1.7.2

3 years ago

1.7.1

3 years ago

1.7.0

3 years ago

1.6.12

3 years ago

1.6.4

3 years ago

1.6.3

3 years ago

1.6.9

3 years ago

1.6.11

3 years ago

1.6.8

3 years ago

1.6.10

3 years ago

1.6.7

3 years ago

1.6.6

3 years ago

1.6.5

3 years ago

1.6.2

3 years ago

1.6.1

3 years ago

1.6.0

3 years ago

1.5.8

3 years ago

1.5.7

4 years ago

1.5.6

4 years ago

1.5.5

4 years ago

1.5.4

4 years ago

1.5.3

4 years ago

1.5.2

4 years ago

1.5.1

4 years ago

1.5.0

4 years ago

1.4.0

4 years ago

1.3.3

4 years ago

1.3.2

4 years ago

1.3.1

4 years ago

1.3.0

4 years ago

1.2.0

4 years ago

1.1.1

4 years ago

1.1.0

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago

0.2.0

4 years ago

0.1.0

4 years ago