diff --git a/blog/posts.json b/blog/posts.json index 14bfaa7..4226b81 100644 --- a/blog/posts.json +++ b/blog/posts.json @@ -39,5 +39,11 @@ "id": "big_projects", "date": "9/15/2019", "discuss": "https://twitter.com/Ellpeck/status/1173247686654517249" + }, + { + "name": "How to make a Rock Bottom mod", + "summary": "My adventures back into a game I stopped working on about two years ago and how I start on a mod for it", + "id": "rock_bottom_mod", + "date": "10/3/2019" } ] \ No newline at end of file diff --git a/blog/res/rock_bottom_mod/1.png b/blog/res/rock_bottom_mod/1.png new file mode 100644 index 0000000..9a060f8 Binary files /dev/null and b/blog/res/rock_bottom_mod/1.png differ diff --git a/blog/res/rock_bottom_mod/2.png b/blog/res/rock_bottom_mod/2.png new file mode 100644 index 0000000..edb27ac Binary files /dev/null and b/blog/res/rock_bottom_mod/2.png differ diff --git a/blog/res/rock_bottom_mod/3.png b/blog/res/rock_bottom_mod/3.png new file mode 100644 index 0000000..3380797 Binary files /dev/null and b/blog/res/rock_bottom_mod/3.png differ diff --git a/blog/res/rock_bottom_mod/4.png b/blog/res/rock_bottom_mod/4.png new file mode 100644 index 0000000..0448b26 Binary files /dev/null and b/blog/res/rock_bottom_mod/4.png differ diff --git a/blog/res/rock_bottom_mod/5.png b/blog/res/rock_bottom_mod/5.png new file mode 100644 index 0000000..38b2b56 Binary files /dev/null and b/blog/res/rock_bottom_mod/5.png differ diff --git a/blog/res/rock_bottom_mod/6.png b/blog/res/rock_bottom_mod/6.png new file mode 100644 index 0000000..6b59820 Binary files /dev/null and b/blog/res/rock_bottom_mod/6.png differ diff --git a/blog/res/rock_bottom_mod/7.png b/blog/res/rock_bottom_mod/7.png new file mode 100644 index 0000000..a9b2c1f Binary files /dev/null and b/blog/res/rock_bottom_mod/7.png differ diff --git a/blog/res/rock_bottom_mod/8.gif b/blog/res/rock_bottom_mod/8.gif new file mode 100644 index 0000000..ae51fa5 Binary files /dev/null and b/blog/res/rock_bottom_mod/8.gif differ diff --git a/blog/res/rock_bottom_mod/NaturesAuraRockBottom-0.1.jar b/blog/res/rock_bottom_mod/NaturesAuraRockBottom-0.1.jar new file mode 100644 index 0000000..a4822f3 Binary files /dev/null and b/blog/res/rock_bottom_mod/NaturesAuraRockBottom-0.1.jar differ diff --git a/blog/rock_bottom_mod.md b/blog/rock_bottom_mod.md new file mode 100644 index 0000000..fa1f578 --- /dev/null +++ b/blog/rock_bottom_mod.md @@ -0,0 +1,177 @@ +So it's been a hot minute since I stopped working on my first big game project, [Rock Bottom](https://rockbottomgame.com). Since then, I've changed a lot, but the game hasn't changed that much: For a long time, the project was vacant, until I decided to make it open source. From that point on, a couple of my friends started working on it, adding some new features and fixing some bugs, until it seemingly fell back into vacancy over the last couple of weeks. + +So let's port my recent Minecraft mod, [Nature's Aura](https://www.curseforge.com/minecraft/mc-mods/natures-aura), to Rock Bottom! + +***Note: This is not a tutorial.*** + +# Setting up the dev environment +Now I *somewhat* remember that, back when I was working on the game, I set up a pretty in-depth modding API as well as an actual Github project to easily allow people to set up a mod themselves. + +*Aha, here it is: [the modding repo](https://github.com/RockBottomGame/Modding).* It even has some nice documentation that I apparently made! Okay, here goes. + +Okay, finding [a build of the game](https://github.com/RockBottomGame/RockBottom/releases) was pretty easy. It even has an in-depth changelog! Good on you, raphy. + +Hm. Okay. +So something's already broken. +![](blog/res/rock_bottom_mod/1.png =100%x*) + +It looks like here +``` +dependencies { + compile group: 'de.ellpeck.rockbottom', name: 'RockBottomAPI', version: '+' +} +``` +where it says `+`, it should actally be saying a specific version. So let's replace that with `0.4.6-753` and refresh. + +That didn't seem to fix it either. Huh. Taking a look at [the maven](https://maven.chaosfield.at/de/ellpeck/rockbottom/RockBottomAPI/0.4.6-753/), it seems to be currently down because of `502 bad gateway`. Fun. + +Okay, it's now the next day and it looks like the maven has been fixed, which is nice. So all the compile issues are finally resolved, I put the build into the `/gamedata` folder like explained in the tutorial, I renamed the examplemod to `NaturesAura`, and I can now finally try running the game! + +![](blog/res/rock_bottom_mod/2.png =100%x*) +Ah! That worked quite well in the end. + +# Actually making something +So I feel like the first thing I should add to the game is the golden leaves, because they're also the first thing that you have to create when getting started with the Minecraft version of Nature's Aura. + +So I quickly made a new class that extends `TileBasic`, which I vaguely remember was like an extended, better version of the `Tile` class with some useful helper methods. +```java +package de.ellpeck.naturesaura.tiles; + +import de.ellpeck.rockbottom.api.tile.TileBasic; +import de.ellpeck.rockbottom.api.util.reg.ResourceName; + +public class TileGoldenLeaves extends TileBasic { + + public TileGoldenLeaves(ResourceName name) { + super(name); + } +} +``` + +My Java is pretty rusty, but I seem to remember all of the naming conventions and, coming from C#, do find myself having trouble with the lowerCamelCase methods (because C# uses UpperCamelCase for method names, conventionally). I quickly made a `Tiles` class that's going to house all the tiles I create and made an instance of the golden leaves tile. + +```java +package de.ellpeck.naturesaura.tiles; + +import de.ellpeck.naturesaura.NaturesAura; +import de.ellpeck.rockbottom.api.tile.Tile; + +public final class Tiles { + + public static final Tile GOLDEN_LEAVES = new TileGoldenLeaves(NaturesAura.createRes("golden_leaves")); + +} +``` + +I also created a dummy instance of the Tiles class so that the static variables in it are loaded. If you're not extremely familiar with Java, then this might appear a bit weird for you, but static variables of a class only get instantiated once the class is first used in some way (be it instance creation, method calling, stuff like that), and because I want the golden leaves to be initialized in the `preInit` phase of the game, I just do this: + +```java +@Override +public void preInit(IGameInstance game, IApiHandler apiHandler, IEventHandler eventHandler) { + this.modLogger.info("Starting Nature's Aura for RockBottom"); + new Tiles(); +} +``` + +So far, so good. Let's figure out how to add a texture to the thing. +I somewhat remember that I made a horrible json-based asset system (instead of just loading all of the assets in the mod's jar automatically), so I'm going to try to add my tile to the `assets.json` file the example mod provided me with and also add a texture into the actual file system. + +![](blog/res/rock_bottom_mod/3.png =100%x*) +This is the folder structure I decided on. I also created a quick golden version of the game's leaves texture by going to the [asset repository](https://github.com/RockBottomGame/Assets), stealing the leaves texture and recoloring it to be golden-ish. + +Also, I put this in the assets file, but I have no idea if that's actually the right path. We'll find out. +```json +{ + "loc.": { + "us_english": "/loc/us_english.json" + }, + "tex.": { + "tiles.": { + "golden_leaves": "/tex/tiles/golden_leaves.png" + } + } +} +``` + +Okay, let's launch and see what happens. So I started the game, opened a lan server, opened the chat, typed `/items` to get a cheat menu, and... it's not showing up. What did I do wrong? + +After some thinking, it turns out that I forgot to actually *register* the tile. So I went back into my `Tiles` class and appended `.register()` to the end of the whole thing, like this: +``` +public static final Tile GOLDEN_LEAVES = new TileGoldenLeaves(NaturesAura.createRes("golden_leaves")).register(); +``` +*Crisis averted*. + +![](blog/res/rock_bottom_mod/4.png =100%x*) +Yaaay, it... worked? *Somewhat?* + +You're probably yelling at your screen by now, but yes, I finally noticed it as well: My assets path says `examplemod` instead of `naturesaura`. Easy fix, though. + +While I'm at it though, I can also add a localization entry for the golden leaves. When hovering over it, the console informed me that `Localization with name naturesaura/item.golden_leaves is missing from locale with name us_english!`, so I quickly added it: +```json +{ + "naturesaura": { + "item.": { + "golden_leaves": "Golden Leaves" + } + } +} +``` + +Let's try again. + +![](blog/res/rock_bottom_mod/5.png =100%x*) +Ta-da! Success, at last. + +After some investigation, I realized that Rock Bottom's normal leaves can be walked through, so let's see how to make that happen. Typing `@Override` while in the `TileGoldenLeaves` class causes my IDE to list all of the methods I can override. Among them are two that interest me: +```java +@Override +public boolean isFullTile() { + return false; +} + +@Override +public BoundBox getBoundBox(IWorld world, TileState state, int x, int y, TileLayer layer) { + return null; +} +``` +It seems like this is what I have to do to make the tile walk-through...able. Let's try it out. + +![](blog/res/rock_bottom_mod/6.png =100%x*) +Yay, that seems to have worked. Great. + +# Making an item +Now that I have somewhat of a grip of this whole Rock Bottom stuff again, I'm quickly going to make an item. I won't bore you with the details as it's pretty similar to making a tile, but the gist of it is this: I made an `ItemGoldPowder` class that extends `ItemBasic`, and I initialized and registered an instance of that in my newly created `Items` class, of which I created an instance in my mod class's `preInit` method so that it gets initialized at the right time. Also, I did all of the annoying asset mumbo jumbo. + +![](blog/res/rock_bottom_mod/7.png =100%x*) +*Oh, C#, you've ruined me.* + +# Making stuff happen +Now, to actually make the gold powder turn normal leaves into golden leaves, I have to write some actual code that isn't just boring boilerplate. When right clicking the golden powder onto a leaves tile, I want that tile to turn into the golden leaves. Eventually, they should then *transition* somehow, but... I'll leave that for later. + +Let's write some code! +```java +@Override +public boolean onInteractWith(IWorld world, int x, int y, TileLayer layer, double mouseX, double mouseY, AbstractEntityPlayer player, ItemInstance instance) { + var state = world.getState(layer, x, y); + if (state.getTile() != GameContent.TILE_LEAVES) + return false; + world.setState(layer, x, y, Tiles.GOLDEN_LEAVES.getDefState()); + player.getInv().remove(player.getSelectedSlot(), 1); + return true; +} +``` +While writing this code, I quickly remembered that Rock Bottom has a tile state system similar to Minecraft, so I had to work with that. Before I realized, I sat there wondering why `IWorld` doesn't have a `getTile` method anywhere. Anyway, this should check the interacted tile; see if it's leaves; replace the leaves with golden leaves and deduct one from the item being currently held (which is obviously the gold powder, as this is in the `ItemGoldPowder` class. No need for checks there.) + +Let's try it out! ...yea, no. The Java version that gradle uses to compile a Rock Bottom mod isn't new enough yet: You can't use the `var` keyword. Oh, my poor, poor C# soul. So let's swap that `var` out for a `TileState`. + +![](blog/res/rock_bottom_mod/8.gif =100%x*) +Yay, it works! *Except that, in the gif, the mouse position is weirdly offset for some reason. It's correct in person, I promise!* + +# Conclusion +So yea, that was the start of my adventure back into Java, back into my old game and back into... well, modding, I guess. I hope you enjoyed reading this post and seeing my process of working out how to do stuff. + +I think it's important to remember that, as a developer (especially an indie developer), you don't have to code everything perfectly or work stuff out correctly the first try. I mean, heck, this is my own game, and I completely forgot how to make a mod for it. But it was fun to figure it out again, and to get back into something I made two years ago. + +Oh, also, if you really want, [here's a build of the mod](https://ellpeck.de/blog/res/rock_bottom_mod/NaturesAuraRockBottom-0.1.jar) that you can try out yourself, as the game is now actually open source and available to everyone! I created this jar with the command `gradlew build`, and all you have to do to run it is [download the game](https://github.com/RockBottomGame/RockBottom/releases), run it once, and then stick the mod jar into its `mods` folder. It really doesn't do that much right now, though, so I don't know why you'd bother. + +As always, thanks for reading! \ No newline at end of file