12/16/2011
Comments

Minecraft modding, then and now

tl;dr: Potentially upcoming crapfest & drama for MC modding! Whooo.

Added 12/16: Last paragraph

I started making mods not long after the SMP server mod “hMod” came out around September 2010. Before hMod, you had either regular hard-coded mods similar to how you have it on single player or simplistic “server wrappers” that didn’t let you do much to the game itself. hMod was different: it was the first time that you could write “plugins” for the server so that you could easily extend it, and because your plugin would mostly access hMod’s code, you wouldn’t have to update your plugin so much whenever Minecraft got updated. With this fantastic new development, I made WorldEdit, WorldGuard, CraftBook, and CommandHelper over the last quarter of the year. Unfortunately, not only was hMod on shaky legal ground, the code was a complete mess. If you wanted to adjust an event and add new features to it, you’d single-handedly break all the plugins that used that event. I felt uneasy about hMod’s future and wrote WorldEdit and WorldGuard in a way where I could easily port it to some new mod in case hMod died.

Well die it did. Only a few months later, towards the end of December 2010, a few guys secretly started up a project called Bukkit as a replacement. It was to borrow its predecessor’s best ideas while fixing its worst faults. The community for hMod was sizable, and Bukkit needed momentum in order to get adopted, especially as most server owners wouldn’t want to completely dump everything to switch to something completely brand new. With that transition, for better or worse, I helped by declaring that all future releases of my plugins would only be for Bukkit. As my plugins were pretty popular (least to say), especially CraftBook, that pretty much put the nail in the coffin for hMod and gave Bukkit life. I had good reasons to back my decision, however. The author of hMod had completely become unreachable for several weeks, and while Minecraft was still getting updated with new versions, no one left had the ability to post new versions of hMod. That wasn’t good, and it was put the future of hMod in deep question. Giving Bukkit a chance seemed like the best idea. This was around the beginning of January 2011.

I was enthusiastic about Bukkit at the time, and I got WorldEdit and WorldGuard ported pretty quickly (CraftBook wasn’t written to be ported easily, and those who are familiar with CraftBook are probably familiar with its fate). I helped Bukkit by designing the permissions system that everyone uses (with.the.nodes), as well by writing the original configuration classes and vehicle events. For the first month or so, things were rosy, but the frequency of commits to my own projects had started to fall sharply. While I was definitely busier that part of the year, the magic had faded away, and my hope that Bukkit would be the bastion of extensibility had disappeared. While there were technical issues to blame for that, there were also (and arguable still are) very strong opinions among the core team’s members about what people should be able to do and what they shouldn’t be able to do. Politics became an important fact of life suddenly. My frequency of commits to Bukkit fell even sharper. A few months later, unsurprisingly, someone started writing a mod to Bukkit itself to allow you to do things that Bukkit wouldn’t let you do. It was originally named BukkitDev, but later it changed its name to Spout. The community also changed. Everything had become cutthroat, and everyone wanted to be famous and popular (or small-time rich, as the case may be). People would write plugins to do exactly the same thing as another person’s plugins, and often times these copy-cats would even be inferior. I wouldn’t be surprised if 50% of the Bukkit plugins available right now solely exist to block fire and TNT usage.

Throughout this time, While Notch has been fairly indecisive on several occasions, he did have an opinion that Mojang shouldn’t give any preference to any particular user-made mod, and never really endorsed Bukkit, hMod, or anything else. Bukkit entered in discussions with Mojang in early 2011 in hope that Mojang would embrace Bukkit with official support, but these exchanges did not progress at all. This impartiality was a good thing, but it had its downsides. There was always some fragmentation in the community – not everything was happy with what Bukkit did, and others were definitely not a fan of the person who led Bukkit. Canary was born out of hMod as its direct successor (sometime in early 2011), with several original hMod fans as a part of the team, but it never gained traction against Bukkit. I personally never ported any of my mods to Canary after that split happened (mostly due to a matter of time constraints). However, while Canary had really little traction, it always had the chance at becoming the top server mod through hard work and ingenuity, largely due to Notch’s impartiality.

Sometime earlier this year though, Bukkit gained a corporate partner: Curse.com. They’d host the website and also fund the project, but Curse.com also was the owner of the Minecraft forums, which they had purchased previously from a bunch of Minecraft fans who started it a long time back. This obviously gave them an enormous amount of power to move the community in certain directions, and with them behind Bukkit, that meant that Bukkit had resources that no other project could dream of (recently Bukkit got front page attention on the Minecraft forums with a video that reeked favoritism for the server, surprise, that Bukkit’s project leader is an administrator on). About this time, I had started to scale back my contributions to Minecraft, as I figure I’d be in for more doom and gloom again. Those who watched me on GitHub closely may have noticed that my contributions to my own plugins and completely evaporated since summer of this year and I’ve been thankful to all the other people who have picked up the slack.

The news now is that, with Notch having moved on and jeb having taken the reins of the project, Bukkit will be responsible for the client modding API. I can’t confirm that particular fact (I’ve been pretty disconnected for the past few months), but I’ve heard that a lot of modders are not happy. Notch is no longer the lead for Minecraft, and so it would not be unreasonable for this decision to have been made. The problem that some modders have with this is that Bukkit has been exceptionally limiting (especially evident by the need for BukkitDev/Spout) and so a number of modders fear that they won’t be able to do all the great and cool mods used to be able to do. The opinions of the core Bukkit team have always been strong in allowing some mods and disallowing others. If this is so, the multiplayer and single player modding communities will finally merge in an official capacity.

When you’ve got two sides with grossly different opinions, there’s a minor chance that the community will fragment. I’ve heard wind of a few plans from various people myself, and we may have a modding community split brewing for the future. If that does happen, it’d be interesting as to whether the other side would be able to muster the clout, as Mojang will control the client and the forums will not be in impartial hands. As for me, I have to say that I have enjoyed Minecraft a lot, a lot more than any other game that I have played. Notch and the Mojang team have done a great job at making such a fantastic game, and I’ve met a lot of great and creative people throughout my time in the community. I’m not disappearing by any means, and I’ll probably be popping in still to manage my plugins, but I’m officially going to watch things settle down, hopefully this time for good, whenever that may be.

I’m not advocating for any option here. I’ve tried to keep politics away from my contributions, as most of us here, including myself, are here to have fun. However, if anyone wanted to see a server-client modding framework that has worked especially well though, you only need to look to the fabulous work in Garry’s Mod. Servers can (safely) send entirely self-contained client mods (written in Lua) to connecting players, which would work wonderfully in tandem with mods on the server. There are completely brand new gamemodes on plenty of servers. Minecraft modding, on the other hand, has been grossly inferior – full of politics and filled with the great rise and fall of many mods.

On another note, I actually worked on a server-client modding framework with lahwran and some other folk many months back (we even registered a domain name in June 2011). The idea was that servers would be able to send client mods to clients, and these mods would access a completely abstracted sandbox API. However, when that failed, it was still possible to also load separate client .class mods (not auto-downloaded, however), so you’d basically have the best of both worlds. Single player mods could also be written under the API. The main issues of the time were that Java is exceptionally un-dynamic, so giving mods the expressive power they needed was difficult. Sandboxing was a difficult matter, and we weren’t even sure if we should let mods access OpenGL, as there are already webpages that can crash your graphics drivers, simply because they have limited access to OpenGL (though no worse exploits exist, as far as I know). A lot of code and planning got done, but we abandoned it because of both time constraints and the uphill climb that we were facing to achieve adoption (it would require both server and client interaction)


12/09/2011
Comments

State of WorldEdit and friends

Currently everything is still maintained (except perhaps CraftBook, but that’s not new news), but a lot of it has been passed on to a few others:

  • zml2008 will be managing release for the most part for CommandBook, WorldGuard, and perhaps WorldEdit.
  • TomyLobo is currently a lead developer on WorldEdit and handles a lot of the cool new features. (He also has a Twitter account.)
  • famerdave will be helping on/off with CommandBook.
  • I will still be around, but sometimes I won’t know the answers to all your questions :)

If you are interested in helping, pop in #sk-dev on irc.esper.net and idle. You may want to get in touch with zml2008 or sk89q to get you started. Please note that you need to be somewhat experienced with Java (or rather programming in general) as I tend to be a pretty strong advocate of abstraction. On the other hand, I wrote WorldEdit when my experience with Java was pretty minimal, so you can do it too (just read up on generics and annotations).

We’re hopefully going to support these projects for as long as possible because I know a lot of people depend on it. Thanks to everyone for supporting us! If you are ever looking for a release and not finding one, you can check out build.sk89q.com for developer builds.


11/13/2011
Comments

Brand new ICs on the Minecraft server

I added some new integrated circuits to the Minecraft server over the past few days. They work like CraftBook but have a number of new features over CraftBook, a lot of them longstanding ideas that never came to fruition. All old CraftBook ICs will still work (and for eternity if possible)!

To make an IC, use ” =icname” (with the space in front). The ID numbers are no longer used — just type the IC name. The text goes on the first line of the wall sign.

Creating the IC

Some helpful information is shown once you’ve created the IC:

After the IC is created

Setup is like CraftBook. You have your families (SISO, 3ISO, etc.).

Setup is like CraftBook

However, unlike CraftBook, diodes are detected properly.

Unlike CraftBook, diodes work properly

Sneaking and right clicking the sign provides debugging information:

ICs can have extra debugging information shown when clicked

Access the in-game documentation with: /reic list, although you can also right click signs (while not sneaking) to see help.

In-game documentation means you don't have to remember it all

For everyone else, you can find the code on GitHub. It’s not standalone yet so you can’t use it, but NeverCast is working on fixing that.


10/12/2011
Comments

How I stay sane while updating my Minecraft server

For my Minecraft server, I often find myself wanting to add a little feature here and there, additions that don’t yet exist or are too minor to bother with searching for a pre-existing plugin. For covering the “last of the mile” and sometimes a little more, I use a plugin specific for my server, but because it’s a little of “everything,” I can’t write it like one big plugin — that makes it difficult for me to maintain it. On the other hand, I don’t want to create a new Bukkit plugin for every little feature because that requires a lot of work to maintain all of them. To fix this problem, my plugin, Rebar (previously gone by with other names), is a little framework within itself that it helps me add new things very quickly, with little overhead and little effort. This is similar to some Python plugin frameworks that I wrote a long time ago, except Python provides you with much more freedom ;)

Components

Pretty much everything is a component. Components know how to initialize themselves as well as shutdown their tasks. They are very light — most components are confined to only one class. When components are loaded, “loader helpers” help initialize the component by automatically linking resources within the class (loader helpers themselves are extensible!). For example, say I want to store sessions in this one component — I want to remember where the last person performed a command, but I only want to keep the data while the user is still logged in. There’s a component for that, and selecting it for this new component is easy with the @InjectComponent helper:

public class MySessionTest extends AbstractComponent {
    @InjectComponent private Sessions sessionsManager;
    // ...
}

What if I need to access another plugin?

public class WorldGuardTest extends AbstractComponent {
    @InjectPlugin(WorldGuardPlugin.class)
    private LazyPluginReference<WorldGuardPlugin> worldguard;
    // ...
}

Because plugins can possibly be unloaded or be made unavailable any time (as opposed to components, which are not outside the world of Rebar), they are accessed through a proxy LazyPluginReference class. We have to specify the class of the plugin in the annotation, sadly, because generics are only known at compile time in Java.

Enabling components is a matter of placing a line in a configuration file. I run two separate servers, a survival and a creative, so often I do not use the same components on both servers.

components:
- com.sk89q.skcraft.users.UserManager
- com.sk89q.skcraft.FancyName
- com.sk89q.skcraft.GameMechanics
- com.sk89q.skcraft.BetterVehicles
# ...

Events

Handling events is the bread and butter of most of the features. Those familiar with the event API in Bukkit know that it’s not a particularly spectacular piece of code though. There’s a lot of code duplicated everywhere, it takes a lot of code to even initiate an event, registering an event handler is a pain, and custom events are a complete joke. I get around some of the issues by using annotations:

@BukkitEvent(type = Event.Type.BLOCK_BREAK)

public class BuildProtection extends AbstractComponent {
   
    public void postInitialize() {
         Rebar.getInstance().registerEvents(new BlockListener());
    }
    // ...
   
    private class BlockListener extends org.bukkit.event.block.BlockListener {
        @BukkitEvent(type = Event.Type.BLOCK_BREAK)
        public void onBlockBreak(BlockBreakEvent event) {
            // Process event
        }
    }
}

Priorities are optionally specified, but it defaults to “normal.”

Custom Events

Rebar has its own improved and fast event system for custom events, and registering event handlers is even the same as the code above. (Java reflection is not at all used except during initialization.) Below is an example of a custom event to check whether a block can be modified. Because the build protection event dispatcher is only active if the build protection component is running, the requirement has to be stated (that’s noted by the @RequiresComponent annotation).

@RegisteredEvent(type = BlockProtectedEvent.class)

@RequiresComponent(BuildProtection.class)
public class ExampleProtectionTest extends AbstractComponent {
   
    public void postInitialize() {
        Rebar.getInstance().registerEvents(new ProtectionListener());
    }
    // ...
   
    public class ProtectionListener extends com.sk89q.rebar.components.ProtectionListener {
        @RegisteredEvent(type = BlockProtectedEvent.class)
        public void onEvent(BlockProtectedEvent event) {
            // Process code here
        }
    }
}

Creating an event is easy:

public class BlockProtectedEvent extends AbstractEvent<ProtectionListener> {
    // Code for the event

    public void call(ProtectionListener listener) {
        listener.onEvent(this);
    }
}

By design, a listener can contain multiple events.

public abstract class ProtectionListener {
    public void onEvent(BlockProtectedEvent event) {
    }

    public void onEvent(GuestProtectedEvent event) {
    }
}

Event priorities are integers, with certain default ones set at certain numbers. This allows for some leeway when setting priority.

Making Events Work

Often times multiple events need to be consolidated into one, or made more specific. For example, say you wanted to protect all signs with the text “[Lock]” on it from being destroyed. If you had to copy the same protection code to each component, you’d find it to be a nightmare! Instead in my plugin, the build protection is handled by a event that is raised by a build protection component. It allows other components to not at all worry about how to protect blocks, just which blocks to protect. It handles dependent blocks as well (e.g. wall signs on a back wall) all in one place.

I pass off a BlockProtectedEvent and whichever component feels like protecting another block can easily handle the event. The code for the actual component that fires the event is shown partially below:

public class BuildProtection extends AbstractComponent {
    public void postInitialize() {
        Rebar rebar = Rebar.getInstance();
        rebar.registerEvents(new BlockListener());
        rebar.registerEvents(new EntityListener());
    }
    // ...
   
    private boolean canModifyAttached(Block from, BlockFace face, Entity entity) {
        // This checks to see if you can modify attached blocks (signs on wall, etc.)
    }
   
    public boolean canModify(Block block, Entity entity) {
        if (Rebar.getInstance().getEventManager().dispatch(
                new BlockProtectedEvent(block, entity)).isCancelled()) return false;
        if (block.getType() == Material.AIR) return true;
        if (!canModifyAttached(block, BlockFace.NORTH, entity)) return false;
        if (!canModifyAttached(block, BlockFace.WEST, entity)) return false;
        if (!canModifyAttached(block, BlockFace.EAST, entity)) return false;
        if (!canModifyAttached(block, BlockFace.SOUTH, entity)) return false;
        if (!canModifyAttached(block, BlockFace.UP, entity)) return false;
       
        return true;
    }
   
    public boolean canModify(Block block) {
        return canModify(block, null);
    }
   
    private class EntityListener extends org.bukkit.event.entity.EntityListener {
        @Override
        @BukkitEvent(type = Event.Type.ENTITY_EXPLODE, priority = Priority.Lowest)
        public void onEntityExplode(EntityExplodeEvent event) {
            if (event.isCancelled()) return;
            for (Block block : event.blockList()) {
                if (!canModify(block, event.getEntity())) {
                    event.setCancelled(true);
                    return;
                }
            }
        }
       
        @Override
        @BukkitEvent(type = Event.Type.ENDERMAN_PICKUP, priority = Priority.Lowest)
        public void onEndermanPickup(EndermanPickupEvent event) {
            if (event.isCancelled()) return;
            if (!canModify(event.getBlock(), event.getEntity())) {
                event.setCancelled(true);
                return;
            }
        }
       
        // ...
    }
   
    // ...
}

Services

Services actually exist in Bukkit (I wrote it), but not many people are familiar with it, and the code is a bit generics-happy, so it tends to scare off people. However, in Rebar, I use them in order to provide a way to plug and play different parts of code and provide a little interop.

An example of a wallet service is:

public interface WalletService {
    void beginTransaction();
    void commitTransaction();
    Wallet getWallet(OfflinePlayer player);
    void saveWallet(OfflinePlayer player);
}

The transaction methods are to ensure the possibility of atomic transactions when dealing with a player’s currency, which allows threading within the plugin as well as access from outside the server entirely.

Registering and working with services is pretty much the code I wrote in Bukkit, so I won’t go deeply into that. However, naturally, I have a loader helper for that:

public class WalletTest extends AbstractComponent {
    @InjectService
    private WalletService wallets;
    // ...
}

Now I can support currency in any component and I don’t have to care as to what is providing the implementation!

Commands

Commands are handled by the command handling code inside of WorldEdit. It features boolean flags as well as flags of other data types (many thanks to TomyLobo), allowing you to do some pretty cool things. Annotations are also used heavily here, with an emphasis on as a little code needed as possible.

public class UserManagerCommands {
    // ...
   
    @Command(aliases = { "update-users" }, desc = "Reload the list of users and their permissions")
    @CommandPermissions({ "skcraft.reload-users" })
    public void reloadUsers(CommandContext context, CommandSender sender) {
        userManager.reload();
        ChatUtil.msg(sender, ChatColor.YELLOW, "Users and groups have been reloaded.");
    }
}

It was this instead of creating a class for each component. I purposely chose not to do that instead back then because WorldEdit had over 100 commands, which would have meant over 100 classes (something I didn’t want to deal with).

Permissions

Permissions are actually handled by WEPIF, which was improved with thanks from zml2008. WEPIF abstracts a lot of the frustrating parts of handling permissions, especially for users of Bukkit’s convoluted permissions system.

Example

Here’s an example of a component that changes your name color to a random one. I don’t designate group colors on my server — everyone gets a random name color so it’s easy to read chat and it’s not cluttered.

public class FancyName extends AbstractComponent {
    private final static Random random = new Random();
   
    public final static ChatColor[] NAME_COLORS = new ChatColor[] {
        ChatColor.GOLD,
        ChatColor.GRAY,
        ChatColor.BLUE,
        ChatColor.GREEN,
        ChatColor.AQUA,
        ChatColor.RED,
        ChatColor.LIGHT_PURPLE,
        ChatColor.YELLOW,
    };
   
    public void postInitialize() {
        Rebar.getInstance().registerEvents(new PlayerListener());
       
        for (Player player : Rebar.getInstance().getServer().getOnlinePlayers()) {
            fancifyPlayer(player);
        }
    }

    public void shutdown() {
    }
   
    public void fancifyPlayer(Player player) {
        player.setDisplayName(
                NAME_COLORS[random.nextInt(NAME_COLORS.length)]
                                         + player.getName() + ChatColor.WHITE);
    }

    public class PlayerListener extends org.bukkit.event.player.PlayerListener {
        @Override
        @BukkitEvent(type = Event.Type.PLAYER_JOIN)
        public void onPlayerJoin(PlayerJoinEvent event) {
            fancifyPlayer(event.getPlayer());
        }
    }
}

Source

Anyway, I actually hope to release some of this framework in the matter of a few weeks, so be on the look out! I’ve been slowly cleaning up things, and figuring out how to make some things less hardcoded (there are some limitations on Bukkit I’ll have to either fix or work around). You can watch me on GitHub if you want. If this article was mostly foreign to you, then you should read up on Java annotations and generics.


10/01/2011
Comments

Economy in a game like Minecraft

The economy of a Minecraft world is pretty fascinating because everything about the world is fabricated players using resources mined from the same world, a feature not present in most games. There are no swords that enter the marketplace through some simulated marketplace, and there isn’t a strong need for such a thing either. Recently, I wrote about an hour’s worth of code for my small Minecraft server in order to allow players to setup shops from chests they owned. They’d place their items to sell in the chest and put a sign above declaring what they’d give for what they’d take. It made trading much easier and an entire trading district blossomed overnight (literally). Because each chest store could only sell up to two items (because two signs can fit above a double-width chest) and each chest took up physical space, it meant that there was a need for players to construct buildings (perhaps large in some cases) for their store. As there was not a “global” market that you could access from any in-game location, that meant that factors that you’d find in the real world such as location had an effect (it’s potentially profitable to start up a series of remote outposts to sell food and arrows). The area of the town at spawn doubled that day.

A shop with in stock and out of stock chests

But there was no currency. I deliberately avoided establishing currency because a number of friends were adamant about not having one, but their disdain for currency isn’t unreasonable. I’ve been around and how “economy” works on many Minecraft servers (as well as other in other games) is through a combination of periodical welfare payments, game-powered shops with rates set by the game, and in the case of roleplay servers, virtual employment. In the case of the shops, rates for multiple items were set by the server owner manually or through a list of item rarities (generated by finding the distribution of materials in a given world). I find the latter particularly farcical – value is very much not simply determined by rarity. On more than a few servers, it seemed as if everyone’s business was to farm sugar cane en-masse – and it worked, because sugar cane as bought by the server’s shops at a fixed price. I didn’t want that and I got the feeling that my server’s players didn’t want it either.

There was, of course, another choice – have algorithms dictate the exchange rate based on the volume of trades by players. A player had suggested this as well, but that meant that I’d have to dedicate time to researching and tweaking the algorithm (although the player said he had some experience with this), plus it’d be open to market manipulation due to the small volume of trades that happens when you only have a smaller server. If I made an error, it could significantly tip the balance the wrong way and I’d have to deal with the aftermath (and after taking a one or two week leave, as it tends to happen). Instead of all of this, I was anticipating that a currency might develop on its own (commodity money). Two different groups of people did setup currency exchanges, but their exchange ratios were not properly fair. One diamond-for-gold exchange ran out of diamond in an hour because the diamond was too cheap for the amount of gold. Beyond that, there wasn’t enough trust to be had for the exchanges and they didn’t catch on.

While bartering has been enjoyable, trading can be challenging because you may not have the item the seller seeks, and you’re also encouraged to delay trade until the real necessity arises. With bartering, some items are impossible to sell because the effort involved in trading for them (and calculating the right barter ratio) is significantly greater than crafting the item themselves, even if prices are as low as you can go. That leaves us with need for an official currency, and probably one that’s driven by money a la a credit card (to lubricate the process even further). We spent a bit of time discussing what to do about that, and I had considered giving everyone a set amount of credits (perhaps 10,000 per head) – something that I can do because it’s a computer game – but I think the currency would never come into use nor stabilize. What we probably will do is setup a certain number of one resource for a certain amount of money at a game-controlled exchange. It’d be a fixed currency backed by gold or something, mostly likely to be something like iron ingots or gold ingots. It seems no one wants fractions either (although decimals is merely a representation), so we’re thinking about having the exchange rate at a large whole number such as $32 for an iron ingot. It has to be high enough to make it possible to trade lower-value items – a great analogy for that, as a friend said, is if the lowest currency denomination suddenly had to be $20 USD, you could no longer trade a large number of objects unless it was in excessive bulk quantities. Another friend suggested using factors of $8, because most items have a stack size that’s 64 or a multiple of 8 – that’s an interesting idea. The question also arises whether we’d want a floating exchange rate in the future too.

One of the currency exchanges

Someone abusing the in-game 'tablet' image board app to advertise

Overall it’s been pretty fun trying to stimulate trade and there has been many analogies to history and real life. Because new versions of Minecraft also continue to come out, the value of items can change. Gold’s value may change in v1.9 because of new items added, and one could currently move money into or out of gold ingots in anticipation, depending on how they expect the value of gold to trend. There’s also been some clever people really working the market (perhaps quite in an evil manner), by, for example, buying out a shop and reselling  with higher markup. Some of the guys on there are younger too, and some of them have really sharpened lately.