Doctacosa

gamedev

In the same vein as last month's post about backups, I also need to manage the disk space taken by the various servers. Laurasia is the biggest concern, as it is the largest server by far. A world border was introduced relatively late for it, so people already had time to explore far and wide. A large circle now delimits the areas available for building, but there's a lot of unvisited areas still.

Once in a while, I'll take Laurasia down for several hours and set off to delete areas that have been accessed yet never built, or that have been left alone for a long time. This makes it easier for the players to find new, untouched places to explore while it also decreases the disk space used by the server. It's a slow process that needs to be handled carefully, but the end result is worth it.

Of course, it's important to avoid accidentally deleting players' creations! As I'm preparing a new trim that should be announced soon, I developed a tool to help me identify what can be done, and I decided to give you patrons an idea on how that looks!

Here's a special version of the map for Laurasia – overworld (link removed). It's generated off the images created by DynMap, to which I've added a layer that displays the coordinates of each server file along with the amount of days that a specific area has been untouched. That data is fetched from the servers files themselves: just like any computer file, the system automatically tracks when they were last modified. A simple color code helps to preview the information:

  • Green: recently updated
  • Yellow: untouched for a year
  • Red: untouched for 2+ years

For something that's easier to see and understand, here's Rodinia's overworld (link removed), which is much smaller. The North-West, South-West and South-East corners haven't actually been visited for about 200 days, while the core areas see a much higher rate of updates.

Going back to the Laurasia display, it's now easier to notice some areas that are good candidates at being deleted that might not have been obvious otherwise!

#gamedev #projects

– Doctacosa

Backups. Always important, and always neglected, right? Minecraft tends to be stable... most of the time, but it also runs into its problems: chunk corruption, unexpected crashes, large-scale griefing, or even the server disk filling out. As such, it's important to keep backups on a regular basis – they've been useful before, so not doing them isn't even an option.

For a while now, my main backup procedure consisted to having a copy of each separate world compressed and stored away, waiting to be used. If the file hasn't been fetched within a few days, it'd automatically get deleted. I'd make sure, once in a while, to download a copy of everything to my own computer as well. I used to keep several days worth of backups on the server at once, but as the worlds started using more disk space, I've had to scale this down quite a bit.

In the meantime, I've learned that my host has a free backup location available for each account. To prevent people from using this to simply extend their disk space, this backup spot is only available through FTP, so you need to connect to it explicitly to upload and download files. I decided to make use of this, and wrote a new Python script to automatically run on a regular basis.

The new process is simple:

  1. For each world: a) Get a copy of the world and compress it. b) Upload the compressed copy to the backup space. c) Delete the local archive.
  2. Backup the database the same way.

Should I ever need to fetch a file from storage, this simple command downloads it back into place:

python3 backup.py -d FILENAME

Moving the files to a different storage location has the big advantage of mitigating risks: if the main dedi's drive fails for some reason, I won't lose both the live games and their backups at the same time.

Another motivation for this improvement is the simple fact that the dedi's disk is starting to fill out. I've got 100 GB to work with, and between the Minecraft worlds, the Starbound universe and various web sections like the images gallery, it's starting to fill out nicely. Ideally, I'd have two servers or drives: one powered by a SSD to run the games, and one on mechanical drives to have a lot more storage. We're not quite there yet, though, and I need to work with what's available. Keeping the backups off location will help to save on disk space as well as make things better organized.

Got ideas on what I should write about in these game dev entries? Please comment with your suggestions!

#gamedev #projects #minecraft

– Doctacosa

As you've seen by now, the custom ranks feature has been put online thanks to the latest wave of improvements to the chat server. To allow this to take place, the messages are now generated by the chat server itself and sent pre-formatted to all Minecraft instances; these only need to display it through a /tellraw command. A side effect is that all public chat now needs to be relayed through said chat server: if it fails for any reason, including bugs and crashes, players in-game will no longer be able to view messages at all. Thankfully, the system has proven to be solid and reliable since it first came online, so I'm comfortable with this change.

Now, how does this works? That chat server maintains a direct connection to the MySQL database, so it's able to read the access level of each player (admin, op, helper, ...) along with their status (contributor, Patreon backer) and any custom titles set. It takes that information, the received message, and puts it all together for display.

There are still a few aspects that I want to add now that the foundation work is solid:

  • At this time, the chat sent from Discord and IRC only displays the [Discord] and [IRC] tags respectively. Why not go the extra step and have them display the actual rank of the chatter? We already have matching groups on Discord for all staff positions, so that could be reflected in-game. Likewise, authenticated IRC users could be identified based on their user status (aop, hop, etc.).

  • One thing I want to investigate is to allow people to /msg others cross-servers. I already overrode the standard chat and /me actions, so I believe that /msg is doable as well. This would make it more convenient to stay in touch with others while hopping around worlds and servers.

  • As a longer term target, possibly have death messages carried over to Discord and IRC. That would provide more context to the chatters; how many times has someone said something like “Why are you yelling? Oh, creeper got you. Nevermind!”? Carrying the cause of kicks could also help the staff identify people who might be using flight mods. And hey, if I can read and propagate death messages, why not replace them with some custom ones at the same time...? Maybe even get some community input on new messages to make things interesting! How does that sound?

#gamedev #projects #minecraft

– Doctacosa

As a new dev entry, here's why and how I introduced the recent chat server.

From day one, when I introduced multiple Minecraft servers (first Rodinia, then Gondwana, and so on), I relied on IRC to carry the messages from location to location. Each server would spawn an IRC bot that'd be used to join #interordi-mc to send messages, read them and show them in game. Rather simple, and it works. The first version of this setup used a Minecraft plugin, which eventually I replaced with my own server wrapper when said plugin seemed like it would no longer be updated. This also allowed me to make a universal chat solution that worked for Bukkit/Spigot instances, Forge setups, and even vanilla Minecraft itself.

Some of you might have seen me running some tests with Discord earlier this year. This used a IRC <–> Discord bridge, where another IRC bot would be used to relay messages to and from Discord. This created the following structure (only showing three Minecraft servers for the example's sake):

Chat structure, take 1

This meant that messages travelling from Laurasia to Discord would absolutely need to go through IRC. The end effect is that messages as seen on Discord would look like this:

CreeperDiscord <CreeperLaurasia> (Doctacosa) Hello there!

That's a bit wordy, isn't it? Additionally, I had no control whatsoever over the formatting. What I wanted to get is closer to this:

CreeperDiscord (Doctacosa) Hello there!

Much better, isn't it? It's more readable, too. To do this, though, I needed to get IRC out of its position as the messages middleman. I eventually got the idea to write my own relay station of sorts. All of the various chat locations (which I've named internally “channels”) would send their messages there, and the server would accept and transmit them to all other channels. The new setup took this form:

Chat structure, take 2

Eventually, I settled on this text format:

Creep [Laurasia] (Doctacosa) Hello there!

I shortened the original “CreeperDiscord” to the more compact “Creep”, and decided to include the location name so people would know if a chatter was on Discord, IRC, or directly in-game. People seem to like having that information available, so that will be here to stay.


Of course, as I mentioned before, having that new chat core in place opens more options. I've reintroduced today the .players command, which now works from in-game, IRC and Discord. As an extra bonus, it's able to relay the list of persons connected on IRC and Discord as well. Those custom ranks I talked about in my previous post? They'll be read and attached to messages by the chat server directly, making sure that the information is always up-to-date everywhere. Other additions could happen at a later time, too!

Got an idea on what topics I should write about in future Game Dev entries? Send in your suggestions in the comments!

#gamedev #projects

– Doctacosa

The problem with being a systems administrator is that, if you do your job properly, no one is likely to notice. I spent some efforts in the past week to improve how I manage things with the Minecraft servers, and figured I'd explain here how the process went! The problem

Running a single Minecraft server was easy. Updating? Take server down, swap files, bring back online, done. Then I introduced Raw (now Rodinia). I had to do it twice over. Simple enough. Then Gondwana got split off. Then Avalonia. Then the Lobby. And so on.

As it stands right now, with the additions of minigames, I'm running 11 Minecraft server instances in parallel. Updating to new versions means taking down all 11 servers, replacing the appropriate files, then bringing them online. The same goes for security and performance fixes, and this is a significant work load at this point. It's also easy to make mistakes: if I keep an older version of, say, one of my plugins on a random server, it may still work yet contain a bug that I assume has been fixed for weeks. This happened more than once, and I wanted to streamline the entire update process.

The solution

What I did is create a server launcher. Instead of simply starting each Minecraft server directly (or really, my server wrapper that takes care of launching the server instance), I call that script instead. Written in Python, every time it is run, it copies some files from a central location, places them in the server's directory, then runs the server. The end result is that, every time a server is launched or restarted, it automatically grabs the latest files I've made available to it, ensuring that everything is up to date. This currently includes the Spigot build (the game proper), my wrapper (used for IRC link-ups and remote control), along with my custom-made plugins. New files can be added to that as I need to.

Of course, this raises the issue of updating the launcher itself whenever I want to automatically copy new files, and I don't want to do that either. Thanks to Python's modular structure, I've got a single copy of the core launcher in the shared directory. Each server has a mini-launcher, not likely to required any changes, which is used to call the main one. If I want to keep a new file updated, I only need to edit the one central location.

The result

Keeping a server up to date is super simple now. I place the updated files in the centralized location as soon as they're available, then restart individual servers whenever it's convenient. A simple command is used for each instance: python3 launch.py. And it's done!

I hope you found this insight interesting. Again, feel free to let me know if there's a topic that you'd like me to expand on in a future post! :–)

#gamedev #projects

– Doctacosa