Zipping Configs for Great Laziness

Okay, I’ll be perfectly frank – using the <ConfigFile/> directive in MCU is usually more trouble than it’s worth. Hear me out, I’m not crazy, honest.

The case for laziness

Providing config files is important – but 99.872% of config files either don’t matter to the client or are full of defaults anyway.

This is especially true if you are running Minecraft 1.7 or later. In the beforetime (ie, back when we wrote the current ServerPack XML schema), servers had to ship tons of config files to make sure everyone’s block and item ID’s matched. Standing up a new modded server was more ID conflict resolution than anything else.

But MC1.7 did away with most of the troublesome ID’s, so that’s not a big deal any more.

So now, most configs control things like difficulty settings and drop tables and stuff like that – stuff that only matters to the server.

And of course, then there are the mods that sync their configs with the client from the server directly… 😉

Therefore, I believe that server maintainers are better off:

  1. Only providing config files that matter to the client
  2. Serving those config files in one big zip file

My usual method

On my servers (with say 80 or so mods), I might have 2 <ConfigFile/> directives in the entire pack – and these would be exclusively <NoOverwrite/> configs so I can provide players with sane defaults for settings that they will likely be changing on their clients (like fixed keybindings or the like).

Every other config file that I need to ship goes in one big zip file that I distribute as an Extract mod. When I edit any config files, I rezip the config directory, recalculate its MD5, and I’m done.

The real benefits

There are a lot of functional reasons why doing things this way.

The biggest reason to me personally is that it makes the XML file easier to look at and edit by hand. Obviously this doesn’t matter as much for people who’re relying on tools like FastPack to do all of their pack updates for them.

The biggest reason everyone else should use this method is that it’s a better experience for end users. When you ship 80 mods and 100 config files, that is 180 files that MCU has to scan with each update check. It’s 180 files that have to be downloaded individually from a server on a fresh install – and if you change 20 config files, that’s 20 files that need to be downloaded for that update.

Even though plain text (like config files) compresses very well (75-90%), zipping them doesn’t save a ton of bandwidth since the files are already so small to begin with. Using a real world example, I have a config directory here with 118 files in it. Uncompressed, that is 1.1mb. Zipped, it shrinks down to 196kb, or a bit over 80% savings… but the real savings isn’t the ~800kb shaved off of the top of a full install.

What it does save is round trips to the web server. Downloading one file is always faster than downloading one hundred – even if they all add up to the same total size of the single file – just because the server is having to start and stop a new download each and every time.

Even if the total huge zip file is bigger than the sum of a dozen updated configs when you’re making a change, the one MD5 check and one download will be nicer for any machine capable of running heavily modded Minecraft in the first place.

There are downsides?

Of course there are. The biggest downside is that you can’t tell what configs are being provided by a pack without actually looking inside the zip.

Additionally, you can’t just change a config file without rebuilding the whole zip (but you’d have to tweak the XML in either case anyway).

Also, if you are using SMB’s incremental pack method, this method really isn’t as appropriate – and you’re probably better off doing things the way he manages them.

How I really do it

Remember how I said I wasn’t crazy? Well, I’m still not. I don’t do this by hand, I wrote a short shell script that does all of this for me.

The absolute last entry in the pack XML will look something like this:

<!-- zip file containing all configs -->
<Module id="configs" name="config files">
    <URL>http://files.mcupdater.com/packname/config.zip</URL>
    <Required>true</Required>
    <ModType inRoot="true">Extract</ModType>
    <MD5>a8196a5d89d752608089ca293c2f90a9</MD5> <!-- auto:config.zip -->
</Module>

That auto:config.zip bit there is important, it’s how my script knows what MD5 to update:

#!/bin/sh
rm config.zip
zip -r config.zip config/
MD5=`md5sum config.zip | cut -f 1 -d ' '`

sed -i.bak 's#<MD5>.*</MD5> <!-- auto:config.zip#<MD5>'${MD5}'</MD5> <!-- auto:config.zip#' ServerPack.xml

diff ServerPack.xml.bak ServerPack.xml

And that’s really all there is to it. I update the contents of the config directory to match my changes and I run the script.

I usually do this directly on the file server, where the config.zip, config/* files, and pack xml are all live versions. When I make this change and push the button, the pack is updated immediately and the next user to update will grab the new zip.

The end result is that I am able to update config files this way faster than by using any other method (fastpack, by-hand, etc…) – so I don’t feel a need to push off config tweaks to a major update cycle. If we need to change a setting on the server, we’ll change the setting, I’ll upload the file, pull the trigger, and the players will have the change before the server is done rebooting.