Amazon Ad

Wednesday, May 24, 2017

Custom Commands

I decided to do a tutorial on commands since there aren't really any tutorials on commands these days. So without further-a-do, let's get to it.

Remember at part two of setting up with IntelliJ while we were creating the proxies, we created two extra methods called "serverStarting(event)" and "serverStopping(event)"? Well, it's now time to utilize them...well...one of them at least! We are going to need to use the "serverStarting(event)" method to register a command to the logical server. So we need to create that same method in our main mod class, annotate it with "@Mod.EventHandler" and pass in "FMLServerStartingEvent" into it. It's going to contain a method we need in order to register our command. (Doing this for "serverStopping(event)" is optional since we are currently not using it).


Now we need to go into our CommonProxy class and register our yet to be created command.


Now we need to create a new class called CommandTutorial and we will put it in a new package called "command". This class needs to inherit from CommandBase, which is a base template for all commands in Minecraft. You will be prompted to override a few methods: "getName()", "getUsage(sender)", and "execute(server, sender, args[]) throws CommandException". For the "getName()" we are going to return the name of our command, which is going to give our command the "/<name_here> <args_1> [args_2] ... [args_8]" look, and the args[] is everything typed after the name of the command separated by spaces. So for the tutorial we should give our command the name "tut", for simplicity and consistency. The "getUsage(sender)" method is returned to us when we try to get the usage for that command. The "execute(server, sender, args[]) throws CommandException" is what we want to happen after the player presses enter with our command entered in. So we are going to specify that.in our "execute()" comand.

First, we need to get the world of the command sender. The command sender is whomever is sending it, the player practically, and get's the entity world out of it. Then we need to check if we are on the client side or on server side. Again, using world.isRemote to check that means that returning true is on the client logical side and returning false means server logical side. We should also print depending on which side we are on just in case we missed something.



Now we need to specify what we want to happen if we are processing on the server logical side. We are going to make a test command that will give us our custom blocks and items specifically. So we will need to get the player that is sending the command. Luckily, we don't need to do any witchcraft to pull that off, cause CommandBase has a method for getting the player; two methods, in fact. We are going to need to use one of them. There is "getPlayer(server, player, name)" and there is "getCommandSenderAsPlayer(sender)" which returns the player that is sending the command. We need that one. So let's create a new EntityPlayerMP object called "player" and initialize it to "getCommandSenderAsPlayer(sender)" and pass in "sender" as an argument. Now let's move on to the part of deciding what block or item to give to the player.

In order to tell Minecraft what block or item to give to the player, we need to test if the command looks like this:

/tut get <item:block>

So we need to see if the command sender has typed in "get" as the first argument.


Now if this is true, then we need to see if the command argument after that matches with any of our items/blocks unlocalized names.



Now we need to give the player the items or blocks requested. We need to create a new ItemStack with each of these items/blocks in it. There are two methods that we can use called "getBlockFromText(sender, name)" and "getItemFromText(sender, name)". We can use these when creating the itemstacks of the blocks/items. We give it a string and it matches the string with an unlocalized name of an item or block (depending on the method specified) and returns the item or block that it finds. Then, we can put it in the player's inventory by using a method in the "player.inventory" called "addStackToInventory(stack)". We need to do this for each item and block.


Let's print something to the screen whenever the command is successful!


Now we can test the mod and type in the command and see what it gives us!


It works for the item, and it also works for the blocks. Congrats! You just created a working command!

Multi-Textured Blocks

I know that this is a popular topic to learn so here it is!

Starting off, we need to review how the blocks are rendered in the game. Blocks are rendered using JSON files, or JavaScript Object Notation. When the model JSON is loaded it checks for various variants. These variants are used to determine how the block is then rendered onto the screen. (More information here). The only variant that we want to worry about today is the "textures" variant. This variant is responsible for reporting back to Minecraft which textures in what domain to render on what object. In this case, we want to render on our tutorial block custom textures that I will provide (or you can make your own if you want to). We are going to create grass and dirt blocks. First we are going to rename our tutorial block to dirt and create a second block and name it grass and create a second blockstates and model JSON files. We will call it "tut_grass" and "tut_dirt". Make sure you change the material to ground for the dirt and grass for, well, you know, grass. And also, change the harvest tool to "shovel" so that we can harvest it properly.

We need to make the blocks drop the proper drops. In the grass class, press CTRL+O and type in getItemDropped and press Enter. We need this method to return Item.getItemFromBlock(Blocks.tutDirt). This is going to make the block drop the dirt block instead of itself. If we add this exactly to the dirt class, but replace Blocks.tutDirt with this keyword, then we can ensure that the same thing happens for the dirt. Now we need to add this to the registry so that we can render it and test it. We need to go into the JSON files that we created earlier for the dirt and grass and rename everything, except the grass model file, leave everything there.

The grass model class is going to be different. You may have noticed the there is the variant "textures" and after that there is the child tag "all", which tell Minecraft to apply the following texture to all sides. What we want to do is tell Minecraft to apply certain textures to certain sides, and there are certain keywords to allow that to happen.

If we tell Minecraft to have the parent model be "cube" rather than "cube_all" then we can have a plethora of different faces for our textures. We can tell Minecraft to render a specific texture on a specific face. A face is defined as a side of a block that is facing a certain direction. There are currently, in vanilla,
  • "north"
  • "south"
  • "east"
  • "west"
  • "up"
  • "down"
We can specify a texture on any of these sides as long as we have the parent model of "cube" rather than the traditional "cube_all".

So now in our JSON file, if we specify the parent to be "cube" then change "all" to be various faces, we can achieve what we want easily.


We are telling it on the "up" face, we want to apply the "tut_grass_top" texture, and then the same texture for the "north", "south", "east", "west" faces because these are the sides of the cube. Then the "down" is the bottom of the cube.

We should also tell minecraft to render a particle when we walk or mine it by adding the "particle" variant in after "textures" which is going to give the texture for when we break the block and particles spawn.



Now if we put the following textures into our assets and run the game then we get the following result! Hopefully you do too! You can apply this concept to any block whatsoever.



Tuesday, May 23, 2017

Blocks, Items, Creative tabs, and all review

In the last tutorial, we created a util class that handles the registry and rendering of all of our blocks and items. Now we need to create our blocks and items. First we need to create a package in our main com.[your_domain].tut package and call it init and put two classes in there and called them Blocks and Items. Let's create a block and an item.

First the block in our Blocks class:


Now we create BlockTutBlock in a package called com.[your_domain].tut.blocks.


As I have said before, you do not have to format your code the way you see it here.

Now we have to make a class called BlockBase and put all of our templates.



Now you can create a block and initialize it all in it's constructor, whether you want to give it a light level, a harvest level, or make it just a basic block. Lastly, we now need to register and render it in our RegisterUtil class.


Now we need to create an item.


Then we create the item class and inherit from ItemBase



But wait, what if we don't wanna put our blocks and items into the vanilla creative tabs? Well, we should create a class called CreativeTabsHandler in our com.[your_domain].tut.handlers and put our new creative tab in their.


This creates a new creative tab with an unlocalized name of "tutTab" and we are setting the tab icon to be our newly created tut item.

Now we need to do the JSON's for our block and item. We can just copy from coal_ore and coal JSON's.

The way that IntelliJ creates directories is kinda weird so we will have to go into the actual folder and create the assets.tut.blockstates and assets.tut.models.item, assets.tut.models.block directories. If we go into the external libraries and open the forgeSrc and locate the assets then we can find the JSON files of coal_ore and coal. You can reference earlier tutorials for creating JSON files for blocks and items, nothing have changed. I will provide images for you if you do not know how to make images. I actually have a small Paint.NET tutorial here if you would like to learn how to make basic textures for items and blocks. You'd have to research or find ways into making higher quality textures though. Here is the link to a couple of textures, one of the block, and one of the item. Once you place them in the right directories, and run the mod, then it should work. I have already tested it.

If you have any questions, please feel free to ask in the comments!

Registry and Rendering Utils

Now we need to register and render our blocks and items properly. The last time we did that, we did it in a not so favorable fashion. The way that we did it was like this:

Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(item, meta, ModelResourceLocation)

This is becoming outdated and is now becoming taken over by a new method of rendering. We are going to create a class that will handle our rendering and registering. So let's create a class called RegisterUtil in a package dubbed util with the following contents.


We create a static void method that we will pass in the preinitialization event into (and I will show you why in a bit) and we create two private static void methods with the events needed as arguments as well as Block and Item as varargs. If you don't know what a vararg is, allow me to explain it to you briefly.

A vararg is simply an array of arguments that are dynamic, so you can have as many passed in as you want. You can either have none passed in, or you can have 100 passed in, as long as the variable that is passed in is of the same type. We can utilize this feature of Java to implement DRY (Don't Repeat Yourself).

First we are going to create the block registry and rendering  method before the item method, because we should do the more complicated one just to get it out of the way.

First, we have to create a foreach loop, which is a for loop that creates a new instance of an object and initializes it to an index of an array of the same type.



Now we need to create an ItemBlock for this new block instance. This new ItemBlock must be a constant so that it doesn't get changed in some way (just to be safe).




Now we need to register the block and itemblock. When we initialize the block before registering it (later on) we give it a registry name. That same registry name is going to be passed onto our itemblock. The itemblock is simply the block as an item in the inventory, using the item json model. Before we register these two, we need to make sure that we are not registering it on the server side, and only on the client side. This is why the FMLPreInitializationEvent argument was given as a parameter so that we can check for the client side. If we are on the client side, and not the server side then we can proceed with registering the block and item block.


So what is the "client side" and "server side" you may ask? Well, to put it simply, there is two different clients and two different servers. There's the physical and logical client and server. The physical client is the actual game that you actually play from the launcher. The physical server is the server you connect to when you wanna play with your friends. So running the minecraft_server.jar is known as the dedicated server, or the physical server. Then there is the logical server and the logical client. The logical client is what processes input and sends that input to the logical server. The logical server is what serves the game's logic, such as mob AI, world generation, weather, health, and other game mechanics. When we test for the client, we are testing for the logical sides. We are registering everything on the logical client and rendering on the logical server.

Now that we got that out of the way, we can definitely start rendering. Within this conditional, after the block and itemblock registry, we add our model registry. (Thanks to draco18s for fixing this! This would have caused some issued one the dedicated server!)



You don't have to format it the way that I did, you can put it all on one line, I had to do it this way in order to make the image fit. It's the same method as before, essentially, just called differently. No need to explain anything here. You can go to my previous tutorial on items if you want to view the explanation on it. Now we can move onto items, which is the same process but a bit shorter, but with items instead, and without itemblocks.



For testing purposes, we can added a logger at every step of this "util".



We are logging the unlocalized names of the blocks that are being registered to the console so that we can easily debug where we went wrong with something. And it's nice to know that our code is working well. Now it's time to make some blocks and items.

We are going to want to make a couple of classes in a packages dubbed init and called them Blocks and Items. In there, we will initialize our blocks and items. Then, in our RegistryUtil, we will register and render our blocks and items.

Before we continue, we need to call our registerAll(event) method in our CommonProxy#preInit(event) method, and pass in the event argument as the parameter, and we are good to go to the next tutorial.

Moderate Minecraft Modding Tutorial Part 2: Setting Up with IntelliJ Part 2

Before we start programming, we gotta fix a few things first! We have to set our language level and target level to be Java 8 and setup our run configurations to use the correct modules. First let's go into our settings by opening File > Settings... and then navigate our way to Build, Execution, Deployment > Compiler > Java Compiler. There we should see three modules.


We need to change the Target bytecode version to 1.8. After we change it, apply the settings and return to the main screen. Next we need to change our JDK to Java 8 by going to File > Project Structure > Project. We need to make sure that Project SDK is set to 1.8 and Project Language Level is set to 8. Next we need to go to Modules and go to tutorial > tutorial_main, which is the module we will use for building our mod. This is needs to have the language level set to 8 as well. If you didn't have to change anything then just close out and you're good, otherwise apply changes and return to the main screen.

Now we can finally start on programming!! Hooray! The fun part! Oh but wait! We still need to set everything up! Damn! Well, this time around it'll go smoother than last time!

First we will need to create the main mod class just like last time with the @Mod annotation and the three main event handlers, in a package with the same naming convention as last time (see my first modding tutorial for more details).


Ref is throwing an error at us so we need to create it and put our static constants in it.


Now we need to set up our proxies. We need to create the common and the client proxy. We need to get an instance of the common proxy which we will be accessing the proxy methods through.



Now we gotta create the necessary methods for the common and client proxies. There are two extra methods that I will get into some other time (such as commands). You should make two classes (CommonProxy and Client Proxy, Client Proxy inheriting from CommonProxy) and they should look like these two images:



In our main class, we need to call our proxies in our even handlers and pass the parameters as arguments so we can use them later whenever we need to.


Now we should probably get, for future reference, the instance of our mod.


Next we need to create a logger so that we can log to the console for debugging purposes.


Now we can use this logger in our main methods to signal to us that our mod initialization has began.


If we run our mod, we shouldn't have any problems and we should find our logs in the console during the pre-init, init, and the post-init phases of modloading.

We are now done with setting up! We can finally begin coding our blocks and items!

Moderate Minecraft Modding Tutorial Part 1: Setting Up with IntelliJ Part 1

Hello, everyone! I know I've been gone for a while, and I am sorry about that, but I am back with even better tutorials! I am going to show you how you can make even better mods with even better code! I will start with showing you how to set up your environment with JetBrains IDEA IntelliJ (which is now my new favorite IDE!) Let's start by obviously downloading and installing IntelliJ from here. Once you have gotten that installed, you are gonna want to go and get forge for 1.11.2 into a new separate folder somewhere on your computer. I will be using mappings for Minecraft Forge 1.11.2-13.20.0.2304. We are going to open IntelliJ and click on "Import Project..." (As shown below).


Navigate to your new project folder that you put your forge files in and double click build.gradle. Click Ok and it should open up a new window. (If your window is not dark theme you can configure it by doing some googling *wink wink*).

You're gonna want to navigate your mouse to the bottom left corner of IntelliJ and a list should pop up, including Gradle.



Click on Gradle and a new window should open on the right. Wait for the tasks to load and that might take a little while so give a bit. You should now see something like this,


Open up tasks and you should be able to view a bunch of different tasks. These tasks are performed through Gradle is how Forge organizes itself for obfuscation and compiling, and even releasing (which we will get to in a later post). Gradle is very useful for fetching code from remote locations and even executing tasks for a program. What we want to do is execute two different tasks, setupDecompWorkspace, and genIntellijRuns.

setupDecompWorkspace is going to setup our workspace so that we can view the minecraft source code along with the forge API. genIntellijRuns is going to setup our workspace to work with IntelliJ. When you run genIntelliJRuns, it will ask you to restart IntelliJ, which you will need to agree to do so in order for everything to work properly

To find these tasks you gotta go into tasks and go into forgegradle, and execute setupDecompWorkspace followed by genIntellijRuns. When these two tasks have completed and you have restarted your IDE, then you are going to need to set up your configurations. Before that, we need to refresh our workspace by clicking the refresh button at the top of our Gradle window. Now if you look in your External Libraries you should see forgeSrc-1.11.2-13.20.0.2304. We are now ready to start programming!