Idiomatic Clojure with LightTable
LightTable, the famous innovative IDE (slash reactive work surface, as described by the author) recently got some pretty amazing additions: user defined plugins and user defined custom expressions.
Custom expressions allow users to define functions that get any block of text and replace with the result, stream information back to LightTable, or display the result inline:
The clojure project Kibit immediately came to mind when I saw the new addition. Kibit is a static code analyzer for Clojure that allows you to find a more idiomatic way of writing a given block of text.
So I wrote this short LightTable integration for it. With it, LightTable can replace any s-expression with its more idiomatic version. For instance, this code:
becomes:
To see how Kibit did, here is the before and after shots of the expression broken down in its components:
After:
In order to use Kibit with LightTable, you just need to:
1. add lein-kibit it to your project.clj:
2. add the integration function to your usermap:
The sample project can be found on GitHub.
Viewing 3D Models directly on GitHub
A few months ago GitHub launched an amazing, albeit limited, support for viewing 3D models directly on GitHub. Since obj files were not supported, and are one of the most prominent 3D files on GitHub (with over 195 thousand files listed against 22 thousand stl files) I’ve created Three-hub.
Three Hub is an open source Chrome Extension that shows the 3D models from the model files when browsing GitHub. You can install it directly from Chrome Store. The source for the extension can be grabbed here.
Currently only obj formats are supported, but support for COLLADA, glTF and other formats will be added in the future.
Here are some amazing models you can see with it already:
WebGL breaking into the real world
A few weeks ago I attended the Khronos WebGL Meetup during GCD week. It was a pleasure to see how much amazing real companies got real work got done, many in just one year. Here are some of the highlights:
Shadertoy
A place to share and explore shaders created by many people. Kinda like Github, but for shaders.
Verold Studio
Verold is similar to Shadertoy, but for full 3D models.
Fractured: Fractal Att Studio
Amazing GPU accelerated fractal exploration tool. More on their post
Cesium
Cesium is an open source virtual globe and map engine (source on GitHub). They also have an online InstaREPL like tool.
Goo Engine
Goo engine (which showcases some pretty good demos) is both an 3D Game Engine in WebGL and a distribution mechanism.
Play Canvas
Play Canvas is also a 3D Game Engine in WebGL. Their amazing Doom 3 Gangnam-Style animation got a lot of attention recently.
Mozilla running Unreal Engine 3 on WebGL
Mozilla outdoing themselves again. After their great work with Banana Bread shooting game, they, alongside Epic Games, ported Unreal Engine 3 to WebGL. Well, WebGL and Emscripten optmized to be compiled to their also recently launched asm.js. It was announced a few days earlier, but the Mozilla team was showcasing some new impressive demos.
Moving towards more widespread adoption
At the end I got to chat with Brandon, who did some amazing work with webgl, and currently works on Google Chrome GPU team helping with WebGL development.
We talked about many things, including ASM.js which had just been announced. I also asked him what was the thing that was impeding WebGL to get more traction, and he shared his two cents: getting gigantic asset deployment is a pain. Most 3d applications have gigabytes of assets, and, comparitevely when you are downloading 2GB assets from Steam, you can go to work, leave your computer at home doing the work, come back, and you are done. Storing the assets and running these long requests on the browser is not yet as frictionless as it could be, and that adds barriers to developers going into WebGL.
Finally
If this is not enough, Florian Boesch recently wrote a great post on Why you should use WebGL
Conjcraft: A Minecraft Mod implemented in Clojure
When you don’t create things, you become defined by your tastes rather than ability. Your tastes only narrow & exclude people. So create.
TL;DR: Source here, and here a video of the mod in action:
Conjcraft
Conjcraft is a simple and extensible Mod for Minecraft written in Clojure (and some Java). Besides introducing two new blocks (Clojure and Github, which is hosting the source here), it brings an extremely simple and small DSL for writing Minecraft recipes.
The recipe DSL cleans up on on Minecrafts original one (which is alredy terse for a Java DSL). Compare these simple ones:
addRecipe(new ItemStack(Block.rail, 16), new Object[] { "X X", "X#X", "X X", 'X', Item.ingotIron, '#', Item.stick });
(recipe-dsl {\X :ingotIron \# :stick} "X X X#X X X" 'rail 16)
Small explanation: the Clojure version is essentially the ascii art of this recipe:
Disclaimer: I’ll not try to teach Clojure here (besides saying it is a Lisp). If you need more info, there are great resources on the web.
This gain in expressiveness (which is come from the fact that Clojure is extremely more expressive than Java) is compounded in multiple recipes, specially after defining a consistent character to block/item mapping:
(def char-block (create-input-char-binding '( d dirt o cobblestone g github c clojure r redstone )))
Many recipes can use them:
(defn recipes [] (recipe-dsl char-block "d d" 'github "o o" 'clojure "c c c" 'swordGold "c c c c" 'bootsGold "cgc cgc" 'bootsDiamond "ccc c c c c" 'legsGold "ccc cgc cgc" 'legsDiamond ))
And finally, all of this is encoded in plain text Clojure files, stored in the conjcraft directory inside user.home (which on Linux and Mac OS it is usually the user’s home directory, aka ~).
This way Conjcraft is very extensible, as it allows the users to add blocks and recipes, without requiring Eclipse or MCP, or to recompile and obfuscate the de-obfuscated Java code.
Such simplicity, though, did not come easily…
Origins
One of the things that has always amazed me about Minecraft is how simple its concept is. I believe this simplicity is actually paramount to its success: by giving you very solid and small building blocks (no pun intended), the game steps away and let the user create its own goals and be shine on its own.
This simplicity also lets other developers step in and create a huge variety of amazing mods (out of which, one my personal favorites is the Aether mod, for being a very ambitious project, and showing how much great content you can create on top of such a simple and powerful platform).
“Simplicity Ain’t Easy”: Stuart Halloway masterfully made this argument, exploring what simple is (one of the key points being that simple is “not compound”), its importance, and how Clojure is a simple language, which actually makes it very powerful. Inspired on the simplicity and power of both Clojure and Minecraft (and continuing my healthy(?) obsession with Minecraft and Clojure) it seemed only natural for me to set to create a simple mod on top of both platforms (natural because both of them run on top of JVM).
Modding Minecraft with Java is quite straightforward with the help of Minecraft Coder Pack (aka MCP) and ModLoader. Calling clojure from Java is also very straightforward, to the point that you basically need a Java class like this:
public class mod_Conjcraft extends BaseMod { public void load() { try { File file = new File(new File(System.getProperty("user.home"), "conjcraft"), "conjcraft_main.clj"); System.out.println("Loading clojure mod files from " + file.getAbsolutePath()); clojure.lang.Compiler.loadFile(file.getAbsolutePath()); clojure.lang.RT.var("conjcraft", "call").invoke(); } catch (IOException e) { throw new IllegalStateException(e); } } }
And then I was able to create a very small function, in 5 lines of Clojure, to add a recipe that would take one block off dirt and output 7 blocks of dirt:
(ns conjcraft) (import '(net.minecraft.src Block ModLoader ItemStack)) (defn call [] (let [dirt Block/dirt] (ModLoader/addRecipe (ItemStack. dirt 7) (to-array ["#" \# dirt]))))
This actually works pretty well when using Eclipse, or the recompile.sh script that comes with MCP. The fun really began when I started preparing to release it…
The 1st rule of the Obfuscator Club is:
You can’t defeat the obfuscator. This is actually really important. Minecraft is obfuscated in its original distribution, which makes a lot of sense for a proprietary and commercial game. MCP tools de-obfuscate the original java code from its original form, giving methods and classes names very straightforward and sensible names.
The problem is that, in general, gamers will need your mod in the obfuscate code, as they game expects classes to use the obfuscated names. Therefore you absolutely must obfuscate your mod.
The 2nd rule of the Obfuscator Club is:
You can’t defeat the obfuscator.
Clojure does have the capability of generating .class files with its Ahead of Time (AOT) compiler. Since the obfuscator does not operate on java source code, but on .class files, this could have helped. But it doesn’t. Other languages that run on JVM like Scala (which compiles to pretty Java-like bytecode) and Mirah (which can even compile to Java source code) can actually get around the obfuscator this way, as long as you don’t use features that require reflection.
To understand why it doesn’t work with Clojure, let me show you what this simple AOT example:
(ns core (:gen-class :main true)) (defn -main [] (println "Hello World!"))
With some help of JD-GUI we can see the equivalent Java code of the generated class files, in particular:
public class core { private static final Var main__var = Var.internPrivate("core", "-main"); private static final Var equals__var = Var.internPrivate("core", "-equals"); private static final Var toString__var = Var.internPrivate("core", "-toString"); private static final Var hashCode__var = Var.internPrivate("core", "-hashCode"); private static final Var clone__var = Var.internPrivate("core", "-clone");
These seemly innocuous lines actually break in runtime. This happens because the obfuscator has another very important property: it puts everything on top level namespace (no packages). Note that the package “core” is written as a literal string, which the obfuscator will not touch. And currently there is no way to use AOT with empty namespaces
You could change the Clojure compiler, or use tools to manipulate the byte code on the class files, but there is actually a much simpler solution:
Breaking the rules: Defeating the Obfuscator
Clojure is famous for supporting one of the most powerful types of metaprogramming: template macros. I have not exploited it on the project because macros can be very hard to understand (think of them as functions that take code in its raw Abstract Syntax Tree form, and output another raw Abstract Syntax Tree), and I wanted to keep the project very accessible.
The point is that I used Clojure to generate Java source code, on compile time (the type of metaprogramming you always have the option to use, no matter the platform or base language you are based on).
This is done by the create_constants.clj script, which actually imports the de-obfuscated code and generates a Java file mapping all block, item and material names to their actual objects (the result cannot be published without breaking both Minecraft and MCP licenses, but reading the code you can get an idea of what the result looks like).
Using the property highlighted before, that the literal strings will not be obfuscated, and knowing that the obfuscator will not obfuscate the attribute names of classes you create (only make stripe their package), this static maps are available to be used directly by interpreted Clojure code.
The final element of defeating the obfuscator is the ExtendableBlock class. It essentially takes Clojure functions (clojure.lang.IFn interface), and delegate methods to them (some methods have to be re-exposed even when public, as the original public method names will be obfuscated).
Conclusions
Modding Minecraft is extremely fun, and it gets a lot more enjoying when doing it in languages that that are fun to use. I’ve used Clojure here, but there are many other languages that could have been used. So have fun, and create.
Thanks
Thanks Notch for making Minecraft and supporting the modding community. Thanks for all the presenters at ClojureWest for inspiring me to bring Clojure to new places. Thanks Robert for making one of the best Minecraft modding tutorials out there. And finally thanks to all the creators of MCP and ModLoader for making modding a simpler and pleasant experience.
Implementing Minecraft in WebGL
TL;DR: Source here, live demo here.
WebGL is an amazing piece of technology that enables browsers to natively render hardware accelerated 3d creations (yay, no o3d plugin needed!). I’ve always been specially amazed by what Mr Doob has been doing with his Three.js framework for quite a while (in particular his participation on the ROME project, which I briefly talked about recently). Nonetheless, there are some other amazing WebGL creations around, such as those featured on Chrome Experiments, those crafted by OOS and the projects recently presented on WebGLCamp (not to mention the amazing Team Fortress 2 level vizualizer).
One thing that has bothered me though, throughout all the examples, is the lack of interactivity (one glaring exception was GLGE‘s car demo) .
This seemed to be from the fact the 3d collision is quite a bit more involved than 2d (MIT’s lecture notes on Computational Geometry, and even on Doom 3’s recently released source code, can give you an idea of how much involved it can get). And since this is considered to be one of the important things that 3d games need, I was not happy with my hands off answer of this topic on Hacker News. Thus I took the challenge of making a a 3d game in WebGL with collision detection.
Implementing Minecraft Classic (which is playable online for free) seemed like a good candidate for such project, as its mechanics are simple, and yet meaningful (not to mention that I am big fan of Notch’s creation). If you don’t know anything about Minecraft, I wrote a small intro about it a few months ago.
Three.js was selected as the rendering lib not only because I really like Mr Doob’s work, but also because it has is quite mature, is open source, has lots of examples and provides a very promising starting point: a visualization of a Minecraft world, which includes a noise function for generating it.
So all that was left was just adding Collision Detection. Well… this is where things started getting interesting.
Minecraft Collision Detection Attempt 1: JigLibJS
Jiglibjs is a port of Jiglibflash, which in itself is a port of Jiglib for c++. It seemed pretty promising, since there was some people using it (along with three.js), and I had great success with using physics libs in the past for 2d games, so it seemed like a natural choice.
After getting it to work with a prototype of the game, it became clear that some things were very wrong. The amazing demos were too simple for Minecraft, and the rotation would get really wrong when walking on simple plane surfaces (something I speculate happening due to some numerical stability differences from ActionScript and Javascript, alongside with some AS3-> Flash compiler bugs).
After some fun 4 dimension matrix hacking, and failing to get around the bugs, I was ready to move on. Thankfully I found another port of JigLibJS which seemed to correct such issues…
Minecraft Collision Detection Attempt 2: JigLibJS2
The fact that someone tried to make a more complex example on JigLibJS, failed, but was tenacious enough to write its own AS3 -> JS compiler to make another port (which worked!) made a very positive impression.
It was also very positive the fact that the interface was almost the same to JigLibJS, making the change to the existing code very small. The problems started to come when trying to make the player cube jump: the cube would not always collide with the bottom plane. This was solved by making more collision iterations. Soon enough another problem came up: when trying to move inside an adjacent static cube (even when both the player and the cube were in the same height), sometimes the player would get a rotation. Trying to set it to no rotation every iteration did not actually help, as the player would still sometimes get a vertical velocity when trying to penetrate the block.
Still, rolling my own Physics Engine seemed a bit daunting, and I decided to try out another lib:
Minecraft Collision Detection Attempt 3: Ammo.js
Ammo.js is a port of the C++ physics engine BulletPhysics, that runs on top of the LLVM‘s Javascript port, aka Emscripten. Everything looked amazing this time: the demos not only looked great, but were very hackable, and had no problems that I previously had.
But then it came the time to try to get to more Minecrafty world dimensions. It was a bit disappointing when mere 400 cubes made the physics engine go to a crawl (even when using static cubes). It became clear that I needed O(1) collision algorithms, which is very doable for Minecraft Classic, as only the player can move, and there is always a constant amount of cubes the player can collide with at any given time. And now there were no more libs left to evaluate.
Minecraft Collision Detection Attempt 4: Rays!
Rays are the standard way of detecting line/Object collision in Three.js. A very simple interactive demo by OOS seemed like it could do the trick. It had the advantage of being very simple, and constant time (given that I selected the possible blocks to collide with, as the traditional Ray.intersectObjects actually tries to intersect all objects on the Scene).
The OOS example had some issues (like trapping the player cube when jumping up and down, while hodling the forward key). This was solvable by using 12 rays correspoding to the edges of the cube that represented the player. Actually, this did not help all the time, as some rays would not collide with the world blocks if the ray’s origin inside a blocks’s face. This is a bug yet to be solved, but I got around it by using 24 rays (two directions for every edge of the player cube).
Things were going well enough that I finally moved into adding textures to the game. However, after making the player cuboid have size dimensions to Minecraft’s, instead of having the same size of the world’s cube (which was what I was experimenting with so far), I noticed that the ray would give false positives depending on the height position of the cube. This only happened when the numbers were all too exact, instead of with minor deltas, as you’d expect from using rays cast from the mouse pointer (as it is usually used on Three.js’ demos).
This, and the fact that collision was taking about half the time of every tick (which was constant, due the improved collision algorithm) made me move on to…
Minecraft Collision Detection Attempt 5: Cube Projection
Up until now I had hopes that I would be able to eventually rotate the player cuboid according to its camera. After having so many troubles with so many collision systems, I simplified the problem: collision of unrotated cuboids. This is a really simple problem: from the Separating Plane Theorem, it is easy to see that I only need to see if the orthogonal projections of the cuboids, which, from the Separating Axis Theorem, means I only need to check out if the unrotated rectangles from the projected faces collide, which finally means I only need to check if the projected intervals collide. All of this amounts to 13 lines of Coffeescript:
CollisionUtils = # The two intervals are [s1, f1] and [s2, f2] testIntervalCollision: (s1, f1, s2, f2) -> !(s2 > f1 || s1 > f2) #Cubes are objects with vmax, vmin (the vertices with greatest/smallest values) #properties. Assumes unrotated cubes. testCubeCollision: (cube1, cube2) -> fcol = CollisionUtils.testIntervalCollision for axis in ['x', 'y', 'z'] collides = fcol cube1.vmin[axis], cube1.vmax[axis] , cube2.vmin[axis], cube2.vmax[axis] return false unless collides return true window.CollisionUtils = CollisionUtils
Which in retrospect is what I should have tried in the first place. At least I learned some stuff in the process.
Not quite finished yet: Camera
Paul Irish did a pretty amazing job with the Three.js FirstPersonControls.js, which is the one that powers the Three.js Minecraft visualizer. The problem with this camera is that it makes hard to actually play Minecraft, as its default mode is to be always moving, making hard to place/remove blocks. Real Minecraft uses first person shooter camera which cannot be achieved with current browsers, as there is no way to trap the user’s mouse. Nevertheless, Minecraft on Android uses a touch and drag camera that can easily be implemented in JS. This camera works they same way as the one on Brandon Jones’ Quake 3 WebGL implementation.
Therefore I refactored, and converted to Coffeescript, the FirstPersonControls to work as a click and drag camera. The resulting 86 lines of code can be seen here.
Adding/Removing Blocks
This is where Rays worked really well. In fact, Mr. Doob even have a voxel editor example which shows really well how to make an app that adds/removes cubes on a 3d grid:
The only issue I’ve found was that my floor plane was too big, which messed up the Ray/plane collision in certain angles. So I coded this intersection directly:
getCubeOnFloorPosition: (ray) -> return null if ray.direction.y >= 0 ret = vec() o = ray.origin v = ray.direction t = (-o.y) / v.y ret.y = 0 ret.x = o.x + t * v.x ret.z = o.z + t * v.z return @addHalfCube ret
Conclusions
I felt the result was quite satifying (the live demo, and the MIT licensed source, can both be found on Github):
Granted, it starts skipping frames quite often as you add more blocks. The original example from Dr. Doob’s didn’t because he created a single Mesh (aka object scene) composed of all blocks. Doing such would make adding/removing blocks a lot more involved (or force me to handle some area loading/unloading), which is a project in itself. Note that the rendering, and not the collision system, is the real bottleneck at this point.
All of this made me admire Notch’s work on Minecraft a lot more, as Minecraft can handle over 21×21 loaded chunks of 16x16x128 (over 14 million blocks!) in any given time. The Three.js community had some great insights on how to achieve such performance over WebGL, which requires the use of shaders, which are quite low level (even if you use the respective TDL Google Library for this, or GPipe to write the shaders in Haskell), and would probably require a lot of collision code to be also written in also a very low level language (slash GPipe’s Haskell). I found it also interesting that shaders can be used in some clever ways to improve JS performance.
And finally, it is important to note that a lot of very people a lot smarter than me have been doing some great work to make working with WebGL and making 3d games much simpler.
There are also other renderer libraries besides Three.js: Scene.js, PhiloGL, A3 (recently presented on the WebGL Camp), Coppercube (which is not open source, but can use flash for 3d rendering as well) and GLGE.
Comments Off on Idiomatic Clojure with LightTable