How I Added Lua Scripting to Minecraft

Tasky is a mod for Minecraft that adds Lua scripting to support scripting in Minecraft for automating tasks.

At a high level I just used forge, added the luaj on top of it and built the game with it. Adding functionality and various hooks is the difficult part, but the essence behind processing lua code is simply to convert Java code to lua funcs at runtime. This can be done by extending various OneArgFunction, TwoArgFunction, … with luaj and then adding them to your own custom globals table whenever a lua chunk is executed.

Adding the Lua interpreter to Minecraft

As mentioned, writing the hooks is the tricky part. The reality is that lua code is hard to convert from Java when your Java code is asynchronous. For example, the moveTo() call for Tasky the behaviour was innately asynchronous. I could write a whole other blog post on just the moveTo call itself (how the pathfinding was implemented), but suffice to say it has to be running in a thread pool. This makes stopping the script a lot more difficult since we need to be able to interrupt at any instruction that’s being currently executed in the lua VM while also halting the execution in the thread pool. In practice interrupts are implemented using a separate InterruptLib which is loaded that luaj supports and we send commands to.

We also need to be able to return the result of moveTo and make it appear as though the code is running synchronously, but I did this using a future that we wait on. Oh yeah–and don’t worry, by default the moveTo function has a timeout period that also causes it to halt and return in the main lua VM.

Once moveTo was implemented stuff like adding a looping functionality to hook functions that the user passes in from lua to be executed, like setTimeout in Javascript, was trivial. It’s the same concept.

So far I’ve finished the entirety of the Lua scripting API (it’s functional and users can write scripts to accomplish stuff), and have begun work on documentation. The next feature I wanted to add was the ability for users to add/write scripts without having to open another window or do lookup the documentation necessarily so they can get instantaneous feedback editing scripts in game.

Adding a Text Editor to Minecraft

The text editor is the next thing I began work on. There were a lot of issues in getting the default fonts to render, so I had to override the default font-renderer with my own MonospaceFontRenderer as well as write a lot of container code to layout GUI elements properly. You need to know some basic OpenGL for this part. In general it was a smooth process but very time consuming since Forge modding does not support debug mode. When I used to hack together Minecraft clients I had the power of debug mode which sped up development a lot.

Creating the scroll-bars was a bit of a challenge in and of itself because of the relationship between what I call the editor’s “camera” and floating point arithmetic. Let it be known that I implemented the scroll bar as essentially an anchored element that takes up a certain size in proportion to the maxIndex, windowSize and maxSize in pixels that the scroll bar takes up. I use some arithmetic on floating point shift variables which denote the progress of the scrollbar from 0-1 on the screen. From there, we can interpolate the value of cameraRow in the editor when dragging accordingly.

The text cursor is made by hiding the user’s native cursor and drawing a textured quad of the editor cursor on top of it. It goes without saying that yes, this editor does support resizing.

Speeding up the editor with Piece Tables

A Piece Table is a data structure used to speed up the adds/replace operations in the text editor. Wikipedia has a better explanation than I do of it, but suffice to say it greatly improves speed and lets implementing operations like undo/redo very simple. It’s used in Microsoft Word which is why word is so fast!

Conclusion

Tasky was a 2 month project on and off of work. It’s still not done, but suffice to say it’ll be coming out soon. I know I could have released the finished lua scripting API but I wanted to add GUI interaction so it’s taking more time.

Back