Twitch streamer Strike started a community voting a few weeks ago what game to play next. With the majority of votes for Minecraft, the project has begun.

The Discord vote

The Discord vote

Originally hosted by Nitrado, we noticed that he payed good money for what was essentially a managed service (which is fully understandable). However, with a community this large, paying by slots and RAM was not a model to go for. Instead, six hours before the server should be opened, we decided for a self hosted solution.
The race was on and we had to start at square one. First things first:

The Server

Strike immediately went for a provider that he knew: Hetzner. They provide all different kinds of services, such as Dedicated Servers, Managed Servers, Web Hosting and Cloud. While being a buzzword, there is a fundamental difference in Hetzner’s offering: scalability. Basically, there are a lot (and I mean A LOT) of packages (CPU, RAM, Storage) to choose from and you can swap its spec in a matter of seconds. Most other providers I know can’t even transfer my data from one VPS to another, so that was a new environment for me.
Problem was, I immediately noticed how that environment was fundamentally different from what I knew. Volumes? Network? Do I not have Internet by default? What do you mean “projects”?! WTF is happening?! Until it dawned on me: “Wait, these are containers!”. Yes, you heard that right. The packages are basically containers, volumes and networks connect multiple of these packages together and all of that is called a project.
Since that had been sorted out, we went with the CPX31 and later upscaled to the CX41.

CPX31 and CX41 specs

CPX31 and CX41 specs

Setup

First, the general setup. Every time I configure a new server, some things have to be done:

  1. Creating a different user than root
  2. Adding my SSH Keys to the user so that I can access the server securely
  3. Disabling root login
  4. Disabling password login completely

After that, I just transferred the data from Nitrado to the new server and voilà…

command not found: java

Right.

I really prefer AdoptOpenJDK, just because its open source and doesn’t have such a restrictive licensing from Oracle. Also I decided to switch the server software in favour of Paper; it increases performance quite a bit by incooperating asynchronous functions and tweaks that are not included in the “Notchian” Server.
The only piece missing was the gameplay modifications. While not being in the Dev Team for too long, I knew that the last community server had a lot of issues with griefing other players and fights over ingame items. As you might have already guessed, that is something to avoid when you want to have a good time. On the other hand, managing regions and protections for the users is not a good experience for the viewers nor the moderators. So the search for plugins began… “You need a golden shovel to modify a region and it’s still hard to use”, “16 USD?”, “Buggy”, “Not even maintained anymore”… It was a mess. In the end, I settled with the following:

  • AutoMessager
    For a few funny messages that occasionally appear in chat
  • CoreProtect
    Rollbacks without recovering a whole backup (and lookups who did what)
  • CoreProtect TNT
    So that we know who triggered TNT/Creeper
  • dynmap
    A fully rendered map to view in-browser
  • Essentials
    Essential commands and features. Who would have thought.
  • EssentialsChat
    For group prefixes in chat like [Sub] or [Mod]
  • LuckPerms
    Permission management system and groups
  • Vault
    API for plugins to communicate with each other. Connects LuckPerms with EssentialsChat, so group prefixes are synced
  • Harbor
    Get a community to sleep at the same time and you will know. Also has a cool animation for skipping the night
  • Landlord
    Protection plugin. Chunk based and easy to manage and configure. Doesn’t need admin intervention
  • Poop
    Don’t. Ask.
  • ProtocolLib
    API for the Minecraft Protocol (comm. between server and client). Can’t remember which plugin needs it
  • SmoothTimber
    Falling trees. Ikr?
  • WorldEdit & WorldGuard
    Necessary for Landlords, but also my most used set of plugins ever. Has caused many server crashes in the playtime I have

Customization

Whitelisting

With standard mechanics and plugins in place, one issue remained to be solved. In the end, this was gonna be a sub server, meaning that only viewers subscribed to Strike’s channel should be able to join. Minecraft has the whitelist feature for that, but we didn’t want to bother with manually adding players to this list.
Using the PircBotX library, I developed a plugin that connects to the Twitch chat and listens to the !whitelist command. To receive badges and the subscription state from users, I also had to manually enable the IRC-Capability twitch.tv/tags:

Configuration configuration = new Configuration.Builder().setName(config.getString("irc.user"))
                .addServer(new ServerEntry("irc.chat.twitch.tv", 6667))
                .setServerPassword(config.getString("irc.token")).addAutoJoinChannel(config.getString("irc.channel"))
                .addListener(new IRC()).addCapHandler(new EnableCapHandler("twitch.tv/tags")).setAutoReconnect(true)
                .buildConfiguration();
// check if user is subscribed to the channel (or a mod)
if (!tags.get("subscriber").equals("1") && !tags.get("mod").equals("1")
        && !tags.get("badges").contains("founder/0")) {
    event.getChannel().send().message("@" + displayName + ", you are not a subscriber!");
    return;
}

That way, users can get automatically whitelisted as long as they have the subscriber or moderator badge. Note that I had to specifically check for the founder badge, because Twitch provides the data subscriber=0 for founders, even while they are still paying money!

Emotes

One thing I definitely wanted to implement was having Strike’s Twitch emotes in Minecraft chat. That is not necessarily a complicated task, but to my surprise, it certainly always creates a “wow” effect among users. Since we already had a custom resource pack to override certain textures (minecraft:copper_ingot, minecraft:copper_block…), getting the new symbols on the player’s clients was “easy”.
First, you need a json file that tells Minecraft which unicode characters to replace and what bitmap to use:

{
  "providers": [
    {
      "type": "bitmap",
      "file": "strikefont.png",
      "height": 8,
      "ascent": 8,
      "chars": [
        "\u0900\u0901\u0902\u0903\u0904\u0905\u0906\u0907\u0908\u0909\u090A\u090B\u090C\u090D\u090E\u090F",
        "\u0910\u0911\u0912\u0913\u0914\u0915\u0916\u0917\u0918\u0919\u091A\u091B\u091C\u091D\u091E\u091F"
      ]
    }
  ]
}

Every string in the chars array represents one line in the bitmap. Based on the width and height of your picture, the characters have a different resolution (duh). So, if the bitmap is 512x64px and you have two strings with 16 characters each, Minecraft expects a 32x32 chunk for each character. This is a pretty good resolution for emotes, as you can see here:

The bitmap file

The bitmap file

And with a little bit of coding magic (and regex), strings like strikLUL will be converted to their correct emote representation, with the same rules that Twitch has: (^|\s+)strikLUL(?=$|\s+)

Twitch emotes in Minecraft

Twitch emotes in Minecraft

There will probably be more customizations to come, but for right now, I will leave this post as-is. The community server is still pretty active, and if you want to have a look at a really interesting streamer, please go ahead and take a look at Strike

Until then
~ CodeSalat