This week’s update comes with a feature that might be frowned upon once people discover what lies beneath and we think it’s important that our community is at least aware of what brought us to such a choice. We’re talking about bots on Block League; more specifically, AI-powered bots. Let’s start by taking one step back.
The main issue
A.E.S. is one of those servers that can’t really work if there aren’t other players online. In survival servers, players can build their base, hunt, gather resources and explore the world even if they’re the only ones currently playing. The same applies to creative servers, factions and probably more genres. On a minigame server like A.E.S., on the contrary, people can’t really e.g. explore maps or gather resources: their agency is pretty limited and they depend on other players to actually… well, play.
A normal day of A.E.S. as a graph looks like this: tabula rasa for hours, then some spikes, and if you’re lucky a big spike that can convert into a 1-2h session where you’ll surely meet other users to play with. 
Clearly this doesn’t look very good, because if I have 20 minutes of free time and the server is currently empty, I don’t want to log in and hope for someone to show up in the time I have. For us, as staff, it means that we need to provide a certain amount of server activity at least during the European afternoons (we’re based in Europe and our userbase is predominantly from there), so that people will at least try to log in and check.
Truth be told, we love our users, because they do want to wait those minutes when they’re given the possibility. And when we get those peaks, people actually have a lot of fun - starting from ourselves. Still, it’s not sustainable, and wanting to play shouldn’t become an activity based on connecting and hoping.
Six years of experiments
In these years we’ve asked ourselves many times how to solve this situation. The things that have worked so far are seasonal events, contests and tournaments: every time there is an event (something that usually lasts 2 weeks) we see many users coming and going; the building contest was a success and our users would like to have another one; tournaments usually guarantee a big amount of players the evening of the tournament and, in case of Block League, also during the weeks before that. However, there is a lowest common denominator: all these three solutions require quite some time to prepare and they are points fixed in time. Meaning, we’re sure to get many users only when an event/contest is in progress, or when a Block League tournament is on the way. The rest of the year, not much.
This is what has brought us in the last months to introduce content adding agency to users in the lobby: you can draw on a canvas, entertain yourself with the balloon in the hub, play chess, volleyball. I mean, yes, we had already had some things you could do on your own - namely the Balloon Bop minigame and parkours - but once you completed them, you were back to square one. For how much the situation improved compared to the time these features weren’t a thing, it was still not enough: hours of nothing, sporadic peaks.
Throughout the years we’ve also noticed that updates adding new features (e.g. Block League experience system and the Only Sword mode) brought back users for a few days - and then they disappeared again. Months of work (or years, in case of the exp system) fading in a dozen of hours, not even enough time to check whether new bugs or crashes were introduced - bugs and crashes that would lay around for who knows how much time.
This last point shed some light to the fact that what really makes an online game valuable is not the amount of features; rather, it’s the community behind it. Sure, the game itself is important, but players log in not only for playing a minigame, but also to share a moment with someone they met - even if they barely talk to each other; and we’re really glad of our lovely community, because it makes A.E.S. a nice place to return to. Events, contents and tournaments help, yet bonding is kind of hard when you can barely find someone.
The upstream issue makes things worse: Luanti is still a niche project. In the moment of writing, there are 439 public servers and 377 users online. Most of the servers are empty, with users aggregating into a bunch of them. To give an estimate, only 10 servers feature at least 10 players, and only 2 servers feature at least 20. Both of these servers feature core mechanics you can also experience alone.
Why don’t you dark patterns?
Here’s the catch: we could ditch all the constant brainfuming about how to keep a somewhat active userbase along the day (trust us, brains fume quite often) and opt for the good ol’ dark patterns. If you don’t know what they are, it’s a way to manipulate users so that they do things they wouldn’t really like to do if such mechanics weren’t present (such as playing way more). Sure, we can’t sell you anything, but slipping daily rewards here, reward your time spent online there, design leaderboards so that they suck you in… well, let’s say it’s not that difficult. However, this is not our style.
We respect our userbase, even more if they’re kids - who can be manipulated way easier than adults. This is why, for instance, it took us years to design the Block League experience system, featuring weights and counterweights so as to avoid pushing people into heavy grinding. We feel we have a responsibility towards our users because we are the ones making the tech that brings the games they play to life.
Automate it
Not wanting to use dark patterns brought us to another idea, a painful one when seen through the lens of development: bots.
You see, making a bot means creating an artificial being that kinda mimics players behaviour. This is already painful on its own, it’s not a trivial matter. But it gets worse: Luanti (the tool A.E.S. uses to run) doesn’t really support bots at the moment of writing. So you have to write a hacky implementation of your own plus making them behave like a human. In other words:

We dove into this challenge a few months ago, when Zughy decided to write and support a hacky homemade version of bots in the library we use to run every minigame, arena_lib. In this way, if a minigame wants to add bots, it can follow arena_lib specifics, without reinventing the wheel. Sure, it’s not perfect and there are probably a few hidden crashes we’re still not aware of, but at least it is something and it is what you get when you have to do it on your own (plus you have a whole server to take care of in the meanwhile).
The bot implementation was written for one of our minigames, Colour Jump. The game is quite easy: there are platforms of different colours, the game tells you a colour, and you have to reach the platform of that colour before the time runs out. If you don’t, you fall down and get eliminated.
Making a bot for such minigame was within our reach, as the instructions were pretty simple: when the colour is announced, reach the right platform. That’s it, one simple condition. Both the arena_lib implementation and the Colour Jump bot were written by hand and, after a few bugfixes, the minigame currently entertains at least a few players when they log in and nobody is online. They can actually play. However, Colour Jump can become boring after a few rounds, as we’re talking about a minigame that lasts no more than a couple of minutes. We needed bots for a bigger game.
Block League bots
If making bots for Colour Jump seems reasonable, Block League is definitely a horse of a different colour: aiming, situational awareness, priorities changing according to context, teams, ball to catch to reach the enemy’s base. A true nightmare.
Given we do this in our free time, that nobody is working on a Luanti bot implementation, and that we can’t really code much if there is almost no one to share our progress with, we took the decision to have AI code them for us. Because it’s simply something you can’t do on your own, unless you want to dedicate months to one single task (with a result that is still uncertain), and it is something that might fix a big part of our problems - our users have been requesting bots for years.
Once we took that decision, it was actually time to deal with it. You might think: “Oh, that’s easy, AI did everything for you” and… well, you can’t be more wrong. Giov4 spent weeks learning about how to approach the problem and playtesting the bots; bots that are experimental, as they only work properly on one single map, Station2.
If you were already following us, you might know that this is not the first time we vibecode something: our improved map reset system “suffered” the same fate. But, since we want to be totally upfront with you, it is a different case. We know how the map reset system works, as we’ve also intervened manually throughout the months to tweak some parts and fix some bugs. AI made the boring part that we could have done by hand requesting us weeks, if not months. On the contrary, bots are only a prototype. And frankly we don’t want to spend more time than we already did to make a state-of-the-art code. They are a temporary solution (they don’t even use the arena_lib system) for a severe problem we’ve been facing for years. We hope that one day we can actually have a proper bot implementation we can rely on, but today is not the day and we don’t know what else could work in the meanwhile - yes, we have a couple more ideas, but they take time and, contrary to bots, they’re not expected to have the same impact. Now, if you’re feeling nerdy, you can deep-dive into the following section to learn how they work. Otherwise, skip to the conclusions.
The technical side

First of all, here is the code: https://gitlab.com/giov4/block-league-bots.
A modified Luanti client supplies information about the map and the match, which Python uses to choose actions and control the bot, while a server-side mod manages its participation in the game. These decisions follow a priority-based tree: depending on possession, threats and its role, the bot may recover the ball, intercept its carrier or defend the base; then it calculates how to reach the chosen destination. For walking, A* searches a three-dimensional graph built from the map’s collision shapes, penalising routes close to edges; when planning a route that includes drops, jumps or propulsor manoeuvres, Dijkstra’s algorithm combines walking paths with directional links, including some manually configured in the arena editor for propulsor jumps, whose requirements are checked against the bot’s stamina, health and equipment. The resulting route passes to a movement controller, which translates it into timed inputs and adjusts them as new observations arrive.
Well… all of that still had to survive contact with an actual staircase 😁. On Station 2, the first versions loved walking along the very edge, slowing down and occasionally getting stuck. Then came the game decisions: the shortest route can be a terrible idea if you’re carrying the ball straight past your own goal, and a defender needs to move with the action while still being able to get back. Apparently, standing behind a wall and contemplating existence doesn’t count as defending. I could go on for a long time listing all the various issues, but you’ve got the idea.
Improving all of this required weeks of iterations. Using Playbox, a very useful vibe-coded tool (also used to run tests on mods such as map_octree or skills), we launched ephemeral worlds in containers, had the clients join, and recorded the matches from different perspectives. We watched the videos, identified what was not working, and reported the issues to Codex, which suggested changes to the decision trees and vision systems; after evaluating them, we approved the implementations, put some automatic testing in place so that the system could detect those regressions automatically, and repeated the test.

At first, the tests were short and automated, but we gradually increased the complexity: more configurations, opposing bases, and human players against them. The bots also have distinct roles: the defender primarily guards the base, the attacker advances, while the support bot assists the defender by staying farther back (when playing with you, bots never assume the attacker role).
We deliberately kept the bots as an external client module rather than implementing everything directly in Lua since a fully in-game implementation would have meant touching many in-game systems at once (skills, weapon logic, arena code, server-side prediction and more) before we even knew whether the approach was worth pursuing. The external module keeps the core game modules cleaner, it’s easier to toggle on and off, and means that a failure won’t crash the server, though it consumes a significant amount of RAM due to each client having to load the map mapblocks.
In conclusion
After 6 years of development and struggling, we felt stuck between waiting for who knows how much time for a proper bot implementation, waiting for Luanti to become bigger and maybe having a bigger chance, featuring dark patterns or… well, this. They say machines should do the activities humans don’t want to, so that the latter can enjoy more their life. This was exactly the case. We’d like to be free to think how to improve the server here and there, all those small details, without having to constantly worry about gathering more users. As something done in our free time, it should make us feel good, not stress us.
On the ethical side of things, we’ve used a tool that is usually not associated to ethical aspects to build something that was born so that players can avoid games that are usually not associated to other ethical aspects (and that probably use AI without much thinking). Many things can be said but I guess we’ll leave it to the reader.
In conclusion, we don’t know if bots will work, but we really hope they will. Last but not least, if you appreciate what we do, please support us on Liberapay: even €1 per month can make the difference.
See you in-game!
