npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

molang

v2.0.1

Published

A fast parser for Minecraft's MoLang

Downloads

164

Readme

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.

| Test | Average 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.

| Test | Average 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.