A small RPG & video game company

Name: Scriptmine
Version: 0.0.0
Author: Dennis Payne
License: GPLv3
Operating System: Linux
Website: http://identicalsoftware.com/scriptmine/


My son recently attended a "Coding with Minecraft" at the library. The class didn't explain too much about programming. It was more about exposing them to the idea of what could be done. The class showed them how to run functions to build things.

The instructor had two suggestions for playing with it at home. She explained that ScriptCraft is not the easiest thing to install. The simpler solution was to pay learntomod.com but she provided information for those wanting to install it themselves.

I figured I could install the software but there was another problem. We didn't have Minecraft. Instead my kids have been playing Minetest, an open source Minecraft like game. When initially exposed to Minecraft, they enjoyed watching it but didn't express a lot of interest in playing. Rather than pay for something they didn't seem to want, I installed Minetest and they weren't really interested. Some months later I tried again with creative mode and installing some mods. That captured their attention.


Before the "Coding with Minecraft" class, I looked over ScriptCraft as I expected it to be used in the class. I wondered how much effort it would take to integrate a javascript engine into Minetest and mimic the functionality. Minetest supports scripting via the lua programming language. I did not find any javascript implementations in lua. Which meant I'd probably have to modify Minetest to provide the functionality.

There were several javascript engines which could be used for such a purpose. I settled on trying duktape for no reason other than it seemed easy to integrate. As the class focused on the Drone API, I decided to focus on implementing that subset of ScriptCraft.

Modifying the Minetest engine didn't appeal to me as I doubted such changes would be merged upstream. Which meant I would have to track changes in Minetest and fix anything which broke in my code. I investigated loading shared libraries in lua and found that it has support for that functionality. A quick example from the internet had the lua command line program loading C code.

The key was to create a function luaopen_scriptmine. In the lua code, I added 'require("scriptmine")'. This caused lua to try loading some lua files and eventually trying scriptmine.so. It ran the function mentioned above which can then register functions for use in lua.

In short order, I had Minetest crashing trying to load a shared library. Minetest was compiled with luajit which has the same API as lua. Recompiling with luajit caused the library to load as long as it was in the directory you ran Minetest from.

Lua and Duktape

The Young Person's Guide to Programming in Minecraft begins with a simple echo function. While not as visually impressive as building a castle, the function served as a proof of the concept. Lua and duktape work remarkably similarly. In fact in testing, I had a crash due to using the functions from the wrong library.

For lua, I started by registering the javascript function. This function takes a string and runs it in the javascript engine. It actually ended up taking two arguments to allow it to get the player's name. lua_tostring is used to get the arguments from the lua stack.

Duktape must be initialized before being used. duk_create_heap_default creates to duk_context. Registering C functions is more complex than the lua_register function. You first push the global object onto the stack. This is the global namespace in which you want to add your function. The C function is pushed next. Now you can attach the C function to the global object with a name.

Everything in duktape and lua works in this manner. You push items on the stack and manipulate them somehow. This gets complex sometimes. Especially with two different stacks to keep track of. Some duktape examples kept a list of the stack in the comments. It didn't take long before I understood the reasoning behind this.

With echo working, I moved on to implementing the Drone object and it's box function. The drone constructor was implemented in the C code. Getting the player position from lua proved more difficult than expected. After retrieving the player object, calls to the getpos function failed. To retrieve the getpos function I had to lookup the metatable and find the function in the __index. I don't entirely understand why that is needed for the player object.

Initially only a small number of Minecraft block IDs were supported. Some blocks have no equivalent in Minetest. This could be solved with additional mods or additions within Scriptmine but that can wait. After the first block appeared in the game, solid boxes and hollow boxes soon followed.

Looking to the Future

I looked over more of the functions found in the Drone object and realized the flaw in my design. The Drone object has a function called times. You can use it to repeat actions. For example you might want to place a house, move right some squares and repeat 5 times to quickly build a village. In order to accomplish this I need a history of actions and the ability to replay them. Even without that functionality reimplementing sphere to match the output of ScriptCraft would take significant work.

The best solution was to reuse the work of the other project. Most of the Drone object in ScriptCraft is written in javascript with only a minimal number of calls back to the java code. Ideally we would work from a common codebase for the Drone but Scriptmine supporting that would be difficult. To prove that the idea would even work, I hacked the Drone code. Everything was removed and slowly added back in as they were ready.

The end result allowed scriptmine to go from supporting two functions to many functions. Spheres appeared instantaneously. Hello world written in gold blocks hung in the sky. Rethinking my approach dramatically sped up development. Throwing away code is always hard. Try to look ahead at what will be needed so you can avoid dead ends.

At this point all the javascript code was loaded from scriptmine.js. ScriptCraft allows you to just drop files into a directory and have it automatically loaded. Unfortunately the standard committees have failed to define functions to read directories in C. I decided to use opendir from dirent.h. Hopefully the mingw libraries provide the function.

Where are we?

Not everything is perfect with the new implementation. Attempts to add doors, ladders and flowers have failed. They are not simple node objects as they are in Minecraft. This means my son's request to build a castle remains unfullfilled.

The event capability in ScriptCraft is very large. Some of which have no equivalent notification in Minetest. These allow you to implement new minigames with Minecraft such as cow clicking. At this time, Scriptmine is not focusing on that API.

The plan was to cross-compile a Windows dll. Part of the reason behind this project was to create a bundle of Minetest with Scriptmine. Anyone taking a "Coding with Minecraft" class could then be given this package. It wouldn't have all the functionality but easy setup might win some converts. However when I downloaded the Windows minetest package, I found it didn't include the luajit dll. The lua implementation was statically linked into the executable.

Scriptmine cannot be built to support a statically linked lua implementation. The only way forward is to rebuild Minetest. Initial test shows that compiling the luajit library with a cross compiler is not straightforward. Unfortunately this means a simple Windows build is not currently available.


#1 - tt, Tuesday, July 17, 2018, 22:04:

It would be nice to see this in windows flavor, but nonetheless thank you for getting this going. I too was looking for a way to implement js in minetest instead of lua...

(optional, e-mail address only visible by admins)

Last modified: 2017-09-04, 06:20

© 2009-2022 Identical Games

powered by phpSQLiteCMS