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 🙏

© 2025 – Pkg Stats / Ryan Hefner

ev3rbf-decompiler

v0.0.5

Published

EV3 RBF decompiler: disassemble and decompile compiled EV3G programs of RBF files

Downloads

95

Readme

EV3-RBF-decompiler

NOTE: Deprecated package.
Full functionality transferred to blocklypy library.


EV3 RBF decompiler: disassemble and decompile compiled EV3G programs of RBF files

This library will convert the LEGO standard EV3G compiled files to get disassembled and decompiled.

EV3 programs created with the Mindstorms program are compiled once they are copied to the brick. In the past several teams and individuals suffered from losing their because the original .ev3 file was lost due to PC issues.

While I encourage all teams to do proper backup and versioning - this tool is able to decode and show almost all EV3G blocks and structures compiled by the LEGO Mindstorms. This enables easier understanding of the real code and emergency backup.

Examples usage

See console.ts as an example.

Background

Although EV3G compile is a one way transformation back in 2018, after experiments I found that disassembly and decompile might be possible.

Here we must mention David Lechner's lmsdisasm that is able to create a meaningful disasembly.

Diasssembly

Diasssembly looks like this:

// Disassembly of demo_CityShaper_CraneMission.rbf
//
// Byte code version: 0.57

vmthread OBJECT1
{
1_0:	OUTPUT_RESET(0, 15)
1_3:	INPUT_DEVICE(CLR_ALL, -1)
1_6:	OR32(0, 1, LOCAL28)
1_10:	MOVE32_32(0, LOCAL36)
1_14:	ADD32(GLOBAL40, 1, GLOBAL40)
1_20:	MOVE8_8(GLOBAL100, LOCAL51)
1_25:	ADD32(GLOBAL36, 1, GLOBAL36)
1_31:	JR_FALSE(LOCAL51, OFFSET1_43)
1_35:	ADD32(LOCAL36, 1, LOCAL36)
1_41:	JR(OFFSET1_14)
1_43:	ADD32(GLOBAL32, 1, GLOBAL32)
1_49:	CALL(OBJECT2, 123, 0, 50, 2.25, 0, 1)
1_74:	ADD32(GLOBAL8, 1, GLOBAL8)
1_78:	MOVE32_32(GLOBAL92, LOCAL32)
1_83:	AND32(LOCAL32, 1, LOCAL40)
1_89:	CP_GT32(LOCAL40, 0, LOCAL50)
1_95:	JR_EQ8(LOCAL50, 0, OFFSET1_105)
1_100:	JR_EQ8(LOCAL50, 1, OFFSET1_107)
1_105:	JR(OFFSET1_125)
1_107:	XOR32(1, LOCAL32, LOCAL44)
1_113:	MOVE32_32(LOCAL44, GLOBAL92)
1_118:	TIMER_WAIT(25, LOCAL12)
1_121:	TIMER_READY(LOCAL12)
1_123:	JR(OFFSET1_125)
1_125:	MOVE32_32(0, LOCAL16)
1_128:	MOVE32_32(LOCAL16, LOCAL20)
1_131:	MOVE32_F(LOCAL20, LOCAL4)
1_134:	ADD32(GLOBAL20, 1, GLOBAL20)
1_138:	CALL(OBJECT5, LOCAL8, 101)
1_147:	ADD32(GLOBAL12, 1, GLOBAL12)
1_151:	ADD32(GLOBAL68, 1, GLOBAL68)
1_157:	CALL(OBJECT6, LOCAL0, LOCAL8, 40)
1_167:	ADD32(GLOBAL80, 1, GLOBAL80)
1_173:	ADD32(GLOBAL48, 1, GLOBAL48)
1_179:	CALL(OBJECT7, 123, LOCAL0, 25, LOCAL28)
1_194:	ADD32(GLOBAL64, 1, GLOBAL64)
1_200:	ADD32(GLOBAL56, 1, GLOBAL56)
1_206:	CALL(OBJECT8, 1.5, LOCAL28, LOCAL49)
1_217:	ADD32(GLOBAL60, 1, GLOBAL60)
1_223:	JR_TRUE(LOCAL49, OFFSET1_234)
1_227:	ADD32(LOCAL16, 1, LOCAL16)
1_231:	JR(OFFSET1_128)
1_234:	ADD32(GLOBAL44, 1, GLOBAL44)
1_240:	CALL(OBJECT9, 123, 0, 1)
1_250:	ADD32(GLOBAL52, 1, GLOBAL52)
1_256:	ADD32(GLOBAL84, 1, GLOBAL84)
1_262:	CALL(OBJECT3, 123, 0, 15, 0.25, 0, 1)
1_287:	ADD32(GLOBAL88, 1, GLOBAL88)
1_293:	ADD32(GLOBAL72, 1, GLOBAL72)
1_299:	CALL(OBJECT10, 101, 25, 60, 0, 1)
1_319:	ADD32(GLOBAL76, 1, GLOBAL76)
1_325:	MOVE32_32(0, LOCAL24)
1_328:	ADD32(GLOBAL16, 1, GLOBAL16)
1_332:	CALL(OBJECT11, 2, 0, LOCAL48)
1_343:	ADD32(GLOBAL0, 1, GLOBAL0)
1_347:	JR_TRUE(LOCAL48, OFFSET1_357)
1_351:	ADD32(LOCAL24, 1, LOCAL24)
1_355:	JR(OFFSET1_328)
1_357:	ADD32(GLOBAL4, 1, GLOBAL4)
1_361:	CALL(OBJECT12, 101, -25, 1, 0, 1)
1_381:	ADD32(GLOBAL24, 1, GLOBAL24)
1_385:	ADD32(GLOBAL28, 1, GLOBAL28)
1_389:	CALL(OBJECT4, 123, 0, -100, 4, 0, 1)
1_414:	ADD32(GLOBAL96, 1, GLOBAL96)
1_420:	OBJECT_END()
}

subcall OBJECT2
{
	IN_F LOCAL0
	IN_F LOCAL4
	IN_F LOCAL8
	IN_F LOCAL12
	IN_32 LOCAL16
	IN_8 LOCAL20

2_7:	CP_EQF(LOCAL12, 0, LOCAL73)
2_12:	MOVE32_32(GLOBAL92, LOCAL60)
2_17:	AND32(LOCAL16, LOCAL60, LOCAL52)
2_23:	CP_GT32(LOCAL52, 0, LOCAL69)
2_29:	OR8(LOCAL73, LOCAL69, LOCAL74)
2_36:	JR_EQ8(LOCAL74, 1, OFFSET2_46)
2_41:	JR_EQ8(LOCAL74, 0, OFFSET2_49)
2_46:	JR(OFFSET2_141)
2_49:	MULF(LOCAL12, 360F, LOCAL24)
2_57:	CALL(OBJECT13, LOCAL0, LOCAL8, LOCAL24, LOCAL4, LOCAL67, LOCAL68, LOCAL20)
2_69:	MOVE32_32(LOCAL16, LOCAL48)
2_73:	MOVE8_8(LOCAL68, LOCAL66)
2_78:	MOVE8_8(LOCAL67, LOCAL65)
2_83:	MOVE32_32(0, LOCAL44)
2_87:	MOVE32_32(GLOBAL92, LOCAL40)
2_92:	AND32(LOCAL48, LOCAL40, LOCAL56)
2_99:	CP_GT32(LOCAL56, 0, LOCAL72)
2_105:	OUTPUT_TEST(LOCAL65, LOCAL66, LOCAL64)
2_112:	CP_EQ8(LOCAL64, 0, LOCAL70)
2_118:	OR8(LOCAL70, LOCAL72, LOCAL71)
2_125:	SLEEP()
2_126:	JR_TRUE(LOCAL71, OFFSET2_139)
2_130:	ADD32(LOCAL44, 1, LOCAL44)
2_136:	JR(OFFSET2_87)
2_139:	JR(OFFSET2_141)
2_141:	RETURN()
2_142:	OBJECT_END()
}

...

Decompile

After disassembly we can pattern match the calls and recognize the -unoptimized- code to match the built-in blocks one-by-one. In the disasmebly call parameters are obvious and positional.

1_43:	ADD32(GLOBAL32, 1, GLOBAL32)
1_49:	CALL(OBJECT2, 123, 0, 50, 2.25, 0, 1)
1_74:	ADD32(GLOBAL8, 1, GLOBAL8)

// Checking OBJECT2 	// CALL(OBJECT2, 123, 0, 50, 2.25, 0, 1)
// Found Move.Rotations()	in OBJECT2

This code calls OBJECT2.
The code of OBJECT2 is matching the following pattern:

  1. "MULF" with value of "360" at the first position.
  2. followed by a "PORT_CNV_OUTPUT"
  3. followed by a "OUTPUT_STEP_SYNC"

... that is matching the pattern of Move.Rotations().

The list of parameters: 123, 0, 50, 2.25, 0, 1 reprsenting the block parameters of "Ports, Steering, Speed, Rotations, <skip>, Brake_At_End".