
Note: this post was originally published on Medium in 2022. I'd like to say my writing has improved since then, so please don't judge this post too harshly.
Arguably one of the most influential games ever created is Minecraft, to the extent that the programming and development scene around it has evolved from just modifications to using it as a standalone game platform. However one of the constants is its rather simplistic physics engine, at least in comparison to other similarly-influential releases like Half-Life 2, which popularised the integration of physics and physics puzzles into games. This is fine considering that the game doesn’t need any sort of complicated physics simulations, however I wanted to see if it was even possible to accurately integrate a physics engine into somewhere where it doesn’t really belong. With one small caveat - I was not going to use client modifications, only server-side plugins. This means I have no control over the code of the game application that runs on a user’s machine, only control over the game server that sends packets.
Classical mechanics
The type of physics that we’re aiming to simulate (or at least approximate) here is classical mechanics. This covers the behaviour of macroscopic objects like bullets, crates, cars and even planets, although we won’t be going that far. Perfect for games considering what kind of interactions usually take place within a game world, like a car colliding with a wall or a bullet hitting a door to swing it open.
Considering that I am not smart enough to write my own collision solver (maybe later), I looked to existing physics libraries which I can integrate. The first and simplest solution is the open-source library Bullet, written in C++, which is already used in other applications like Blender. Interestingly it already has a track record of use in Minecraft, through the client mod DynamX, which led me to the question - how did this Java mod use a C++ physics library? More specifically, did they write their own JNI natives or use another wrapper library? Looking into the source, it uses an existing wrapper library Libbulletjme by Stephen Gold, which provides classes and APIs for loading and manipulating the Bullet physics engine state from Java code. This ended up being the perfect library to integrate into the game, since even though other options like JBullet existed, Libbulletjme was actively maintained and was more feature-complete.
Loading the natives
In comparison to other pure-Java libraries, Libbulletjme was slightly harder to make compatible with the Paper server software, which is a modification of the Minecraft server. We need to include not only the library but also load its appropriate native C++ dependencies at runtime, so that it can access Bullet objects. There are different libraries published for different platforms - you can’t load a Windows .dll on a Linux environment which accepts .so libraries. On top of that, the flavour of LBJ is important: this determines whether it was compiled with single-precision or double-precision decimal support (if you know about the precision limits of floating point numbers, and the coordinate space of the game, alarms should be ringing by now).
Even though LBJ has a class for this handling the cases for different platforms (NativeLibraryLoader), I needed to solve the issue of actually acquiring the correct native libraries for the end user. There were two main approaches:
- Bundle them with the JAR file, and extract/load the required ones when necessary
- Download them at runtime
Attempting the first approach, I quickly realised there were too many natives to bundle into one JAR file, considering most would not even be used by the end user, making it a waste of space. Therefore, I needed to find out how to download them when the server starts, which is relatively easy since they are published in the format “(platform)Release(flavour)__libbulletjme.(so/dll)_”, such as “Linux64ReleaseSp_libbulletjme.so”. A couple methods later, the plugin now saves natives in its own data folder, so they do not have to be redownloaded every time the server starts.
Physics spaces
The core concept of Bullet is a physics space, within which bodies interact and can push each other around. Most often, the engine will be dealing with rigid bodies - bodies which have a fixed shape and cannot be deformed - however Bullet can also handle soft bodies, which can deform. Physics spaces must first be created, which my code does lazily for each world (such as the Overworld or the Nether) loaded on the server: whenever a space is requested for a world, one is returned if it already exists, otherwise an empty space is created. However this space is not automatically populated with collision bodies such as blocks and entities, which causes a problem when your bodies want to interact with the game: they end up falling through the ground forever. There were two solutions I saw to tackle blocks here:
- The game loads blocks in chunks of 16x16 columns. Could we generate one massive mesh (therefore one massive body) per chunk when it is loaded?
- Each body is likely to only interact with the blocks immediately surrounding it. What if we only generate bodies for the blocks around all our non-block bodies?
The first approach turned out to be immediately flawed for two main reasons: the speed and the accuracy.
- Iterating all blocks in a chunk can be hard: up to 65,536 blocks have to be iterated with a column height of just 256, and in modern versions of the game this column height can increase up to 2048.
- Generating a mesh of triangles using the GImpact backing shape meant that collisions between even a simple box shape were buggy and inaccurate. Even worse, testing collisions between this shape and our physics bodies adds even more computation cost per physics step.
The second approach solves both of these issues, at the risk of bodies potentially phasing through blocks at high velocities. I’m still not fully satisfied with this approach, but for my purposes it works well enough. Since all bodies in our physics space have an axis-aligned bounding box used for broadphase collision pair generation, we can take this AABB, expand it slightly on all axes, use it to determine which blocks it might collide with (find the coordinates this box intersects with, inclusive on all axes), and generate the bodies for all of those blocks.
Entities were a much simpler problem to tackle, on the other hand: the server exposes events when an entity is added to or removed from a world via the EntityAddToWorldEvent and EntityRemoveFromWorldEvent classes, listening to which we can create and remove the entity’s rigid body in the physics space respectively. Getting the shape is easy too: since the server exposes the entity’s AABB, we can just create a box shape out of the AABB extents which can be oriented. Before every physics step, we iterate through all entities that we are currently tracking and update the positions and rotations of the physics bodies to match the in-game entity - but note that this is a one-way coupling, so physics objects cannot affect the position of entities.
The physics thread
Even though we’ve now got relatively fast physics integration code, there are still situations in which the physics step might take a long time, such as if a lot of bodies were created at once. The server runs most of its logic in a single “main” thread, which we want to avoid slowing down at all costs. This was a hard situation to be stuck in, since physics engines are inherently computationally expensive relative to the other logic we perform in our update loop, so I went back to examine what other sources I could take inspiration from, finding another attempt at integrating LBJ, Rayon. From here, the solution is painfully obvious: run physics steps on another thread, and execute tasks on that thread whenever you want to mutate the physics state.
My first attempts involved many segfaults and crashes. Debugging code that was both running off the main thread and taking place inside native libraries as opposed to Java code was hard due to how opaque the crashes were - it was never a case of simply following the stack trace, but rather going back through the code to find a single operation that just might have caused the internal state of the engine to break completely (and the entire Java virtual machine to halt). Though I did eventually find a method to this madness, which involved moving as much physics code as possible to the physics thread, and only reading state from the physics engine while on the main thread, but never writing.
The result of this hardship led to much greater performance, with the main thread speed now not being tied to physics calculations at all. Neither would slow down the other, making it ideal for integrating into an environment where many other plugins might run their own complex logic.
Rendering
We can now simulate physics in a world and have written code to integrate Minecraft blocks and entities into this physics space, however showing these physics bodies to the player’s game client is harder since we have no direct control over the client’s renderer. We can only send packets to indicate “place a block here”, “spawn a particle here” or “spawn an entity here”. But we’re not quite stuck, since we have one incredibly useful tool: the humble armour stand.
The armour stand is an entity which can display arbitrary items in slots on its limbs, which most importantly for our purposes includes the head. If we were to somehow create a custom item which displays the model that we want to show, we could accurately position it within the world and get it to move along with the physics body it’s representing. And there is a way to do that through resource packs, that allow you to create custom 3D models and which the client is able to download automatically if the server provides a URL to one, meaning this method requires no client mods. By placing our item with a custom model in the “head” limb of an armour stand, and positioning the stand 1.45 metres below our target position, we can make the model’s centre appear directly at the pivot of the head limb.
To handle rotations, we take advantage of the Pose attributes which let you assign an arbitrary rotation in Euler angles (pitch, yaw, roll) to any limb. We also apply some specific display attributes to our model — scale (1.6, 1.6, 1.6) translation (0.0, -6.4, 0.0) — to get our model to rotate exactly about the head limb’s pivot, rather than 6.4 model units (0.4 metres) above the pivot. The only problem now is to convert a quaternion —the physics engine’s internal representation of rotation - to a set of Euler angles. Initially all of my attempts seemed futile since my values would never convert properly, however after realising that rotation order was a thing and changing from doing XYZ order (what I initially thought was correct) to ZYX order (what the game client internally uses) conversions, the resulting values were flawless.
How a rotated model looks on an armour stand.
Double-precision
Remember that note about single-precision and double-precision flavours? Despite the fact that Bullet supports using double-precision floating point numbers, and that double-precision native libraries are provided for download, there were very few methods at the time to make use of the double-precision. Many methods in Libbulletjme that accessed position or rotation data in Bullet ended up truncating the values to single-precision _float_s rather than _double_s, which is a big problem considering a Minecraft world can stretch up to the 30,000,000th coordinate on either the X and Z axes, and floats lose much of their precision at that extreme, to the point where they cannot even represent any value smaller than around two metres. Obviously unacceptable when dealing with a physics engine which operates in the hundredths of metres.
Despite the existence of some dp (double-precision) methods (such as getPhysicsLocationDp), from issue #9 it is clear that the library was not designed with double-precision as a priority. Thanks to the great efforts of the maintainer Stephen Gold, my issue #19 raised awareness of this issue and resulted in v1.7.20 being released, which added the necessary methods that I needed to get this engine working at any coordinate in the game.
The physics engine
After a couple of weeks of work, the engine CraftBullet is now in a usable state, providing the main tools required to work with physics bodies in a world. It now has testing and debug functions for creating a cube launcher, as well as a way to draw the outline of shapes and bodies in the world, but it still has a few drawbacks:
- Physics bodies cannot push entities in the world
- Players cannot collide with these bodies, so cannot e.g. stand on them
- Liquids such as water and lava are not handled specially (i.e. there is no buoyancy)
Despite this, I feel that this project has been successful and has taught me a lot about using and integrating with existing software, rather than always making my own - a lot of the time, others’ code can just be better than my own. I’m looking forward to creating more interesting plugins which can utilise this physics engine, as well as others potentially using this for their own projects!