Hacker News new | ask | show | jobs
by Cogito 4265 days ago
A few comments say things like "they shouldn't include the binaries" or "why can't they just link to the binary, let the user download it themselves" etc.

There may have been a way to achieve that (and we talked about a few of them quite a few times) but it was never as simple as just 'linking to the binary'.

The Bukkit project was actually composed of a few different pieces, designed to make maintenance of the mod manageable across upgrades of the game. This architectural change was one of the main reasons Bukkit split off from hMod in the first place.

There were 4 main codebases in play; the Bukkit API, the CraftBukkit server mod, the reverse-engineering-tools project, and various plugins supplied by the Project or for use as examples.

I go into more detail below, but the reason why just hooking into the binary was so hard is two fold, and meant that CraftBukkit could never really just be a server wrapper.

1. Methods, method calls, and program logic needed to be modified directly to enable things like turning off fire on the server. Anytime the game tried to start a fire CraftBukkit had to fire an event, and allow that event to be cancelled. So CraftBukkit had to be a mod in the purest sense.

2. Obfuscation meant that modified files had to be translated every single upgrade. To reduce this burden large swathes of the code was de-obfuscated, so that the upgrade process was de-obfuscate core code -> translate any mod changes that used obfuscated code -> apply mod changes on top of the core code -> fix the thousands of bugs we missed in the translate step. So much of the mod was on top of this de-obfuscated version of the server that any distribution would require distributing large amounts of de-obfuscated code - there was no other source for this.

So there may have been ways to avoid shipping Mojang code, but it was always going to be a hard slog. When the core team started conversations with Mojang it always seemed like there was never a pressing need, and as I understand it Mojang still hasn't shut down Bukkit. It was a lone developer asserting a DMCA take down.

I would be very interested to know if there is a better architecture that solves these problems, some more of which I have listed out below.

==== More Details ====

The Bukkit API consisted of JAVA interfaces, providing a stable(ish) API against which plugin authors could build plugins, and some glue code to manage the plugins. This had no code from Mojang in it.

The various 'official' plugins were coded against the API, and similarly had no Mojang code in it.

The reverse-engineering-tools project was used to, perhaps unsurprisingly, reverse engineer the official server. A lot of the code had been de-obfuscated, but that de-obfuscation was usually a painstaking task performed by hand. These tools made that process much easier. It included a decompiled version of the official server code, but the project was private and wasn't distributed. Not sure how that impacts everything.

The CraftBukkit server mod of course DID contain Mojang code, the modded server. It's job was to implement the Bukkit API.

The API was almost entirely event based. Plugins would hook on certain events, and the server would wait for the plugins to process the events before continuing with whatever it was doing.

Someone tries to set a house on fire -> LightFireEvent is fired -> NoFire plugin hooks the event -> NoFire plugin cancels the event -> in game no fire is lit.

In order to implement these events, entire code paths within the game need to be diverted, hooked in to, subverted, or replaced. There are lots of ways a fire might start, so we had events triggering when lava ignites a block next to it, and explosion sets some grass on fire, someone uses flint to light a tree, etc. Each one requires

* finding the obfuscated code path that implements the feature we want to hook

* de-obfuscating the code so it is clear(er) to see how to modify it correctly

* modifying the de-obfuscated code to introduce the hooking code, and implement the API

Every time there was an upgrade to the server we would have to map every modification made to the new obfuscated code base. So if CraftBukkit had modified or included a call to an obfuscated method (which happened often enough for it to be a pain) then those changes had to be mapped to the new method signatures of the upgraded server. c(wx, f, b, 23) might now be e(ww, f, b, 23) and translating that to a modified code base can be hell.

The Bukkit team took that process on itself, which is one of the reasons it was so successful. As long as the API points used don't change, a plugin will continue working as soon as CraftBukkit is upgraded.

2 comments

>So much of the mod was on top of this de-obfuscated version of the server that any distribution would require distributing large amounts of de-obfuscated code - there was no other source for this.

How much of the updating and deployment tasks could be done by a script on the user's computer/server? Decompile with MCP and pull in all the changes as patches, like the Craftbukkit github was when I saw it?

Forge was based on decompiling and patching mojang binaries, it works pretty well.
Yeah, as I mentioned we did talk about it a lot. As it seemed like a lot of work, and since mojang had turned a blind eye, the effort never seemed worth it. The core team got bought before it all came to a head, otherwise you might have seen a greater effort to separate the code bases.

I'll have to look in to forge, I haven't yet seen what they are doing, but it sounds interesting.

EDIT: the other aspect was the fact so much code was written against the de-obfuscated version of the code base. There's an argument that distributing that patch would also be distributing mojang code.