jedidja.ca

There's always something new to learn today

Minecraft Camp Conclusion

This is the conclusion to a series introducing 10-year-olds to programming through Minecraft. Learn more here.

What an interesting four days! Time for some reflection...

What Went Right

  • It was fun for everyone. Apart from the pop quiz I gave on the last day :)
  • There was plenty of enthusiasm once a mod was finished and they could see the result. I heard the term "boss" more than once or twice.
  • Having everyone together at the same table made it easier to help more than one child at a time. They can also help each other.
  • They have great imaginations and cool ideas about what to do. It was good to set expectations about which mods we hoped everyone could create by the end of the class.

What Didn't Go Right

  • I need to be a more patient instructor :)
  • Copying code from a flipchart into an IDE that "helps" with auto-complete is difficult...doubly so when your hand can easily brush over a trackpad and hit other keys. It's amazing what "random" things can happen when trying to enter code.
  • Without being able to type at a decent rate (even 15 WPM), minor mistakes make the process even longer and lead to frustration.
  • Age 10 is probably too young for the average child to fully benefit from this camp.

Children and Computers

There is a real need to teach children about drives, directories, files and applications.

For an erudite article on this topic, please read "Kids can't use computers".

Although children these days (hah! I'm old) are routinely exposed to computers (whether it's a PC, iPad, or DS), many lack a basic understanding of how things work.

My (unfortunately) confirmed suspicion is that there is no comprehension of files/directories, applications, or the internet: it's all one big blur that kinda/somehow works. We spent a lot of time practicing copying files and creating directories, but it still hadn't sunk in by the end of the week. I take some solace in knowing this week provided a foundation they could build on over the next couple years :)

Final Quiz

  • What is the difference between Windows/File Explorer and Internet Explorer?

  • What is the keyboard shortcut for File Explorer?

  • What is the keyboard shortcut for Save?

  • What is the keyboard shortcut for Copy?

  • What is the keyboard shortcut for Paste?

  • What is the name of your computer’s hard drive?

  • Name three applications.

  • What application did we create our Minecraft mods in?

  • What programming language did we write our Minecraft mods in?

  • Circle all of the things that are important when writing code:

    a) spelling b) capitalization c) spaces d) semi-colons

  • What do red squiggly lines under your code mean? (2 things)  

  • What did we name our Minecraft package?

The next two questions refer to the following line of code:

public static final Item moustacheHelmet = 
         new MoustacheHelmet();
  • What is moustacheHelmet? a) package b) class c) method d) variable

  • What is Item? a) package b) class c) method d) variable

  • In the following line of code, what is addShapelessRecipe?

    GameRegistry.addShapelessRecipe(
       new ItemStack(Item.diamond), dirt, dirt);
    

    a) package b) class c) method d) variable

  • If we want to store a whole number (without decimal places) in a variable, what type of variable would we use?

    a) String b) int c) float d) char

Running Your Own Camp?

I'd love to hear from you :) If you want any more information on the six introductory emails I sent parents or more details on the experience, drop me a line! My email is "me" [at] "jedidja" [dot] ca.

Mod: Moustache Helmet and Superspeed Boots

This is the fourteenth lesson in a series introducing 10-year-olds to programming through Minecraft. Learn more here.

The class suggested these two mods on the second-last day of class :) I figured it was simple enough to combine them into one activity as it builds on what we did with the chainsaw.

Add a new class, MoustacheHelmet with a superclass of net.minecraft.item.ItemArmor.

Add the following code to MoustacheHelmet.java

public MoustacheHelmet() {
    super(5001, EnumArmorMaterial.DIAMOND, 3, 0);
    setUnlocalizedName("moustache");
    setCreativeTab(CreativeTabs.tabCombat);
    func_111206_d("generic:moustachehelmet");
}

@Override
public String getArmorTexture(ItemStack stack,
                                  Entity entity,
                                  int slot,
                                  String type)
{
    return "generic:textures/models/armor/prestone_1.png";
}

Add a new class SuperSpeedBoots with a superclass of net.minecraft.item.ItemArmor.

public SuperSpeedBoots() {
    super(5002, EnumArmorMaterial.DIAMOND, 3, 3);
    setUnlocalizedName("superspeed");
    setCreativeTab(CreativeTabs.tabCombat);
    func_111206_d("generic:superspeedboots");
}

@Override
public String getArmorTexture(ItemStack stack,
                                  Entity entity,
                                  int slot,
                                  String type)
{
    return "generic:textures/models/armor/prestone_1.png";
}

@Override
public void onArmorTickUpdate(World world, 
                              EntityPlayer player,
                              ItemStack itemStack)
{
player.addPotionEffect(
           new PotionEffect(
             Potion.moveSpeed.getId(),100,2));
}

In our main mod file, create variables for our two new parts of the armor

public static final Item moustacheHelmet = 
              new MoustacheHelmet();
public static final Item superSpeedBoots = 
              new SuperspeedBoots();

and register them with the game in the load method

GameRegistry.registerItem(
      moustacheHelmet, "moustacheHelmet");
LanguageRegistry.addName(
      moustacheHelmet, "Moustache Helmet");

GameRegistry.registerItem(
      superSpeedBoots, "superspeedBoots");
LanguageRegistry.addName(
      superSpeedBoots, "Super Speed Boots");

We'll also make recipes this time (using diamonds, since we already have a mod to create diamonds from dirt)

GameRegistry.addRecipe(
    new ItemStack(moustacheHelmet),
    "XXX",
    "X X",
    'X', Item.diamond);

GameRegistry.addRecipe(
    new ItemStack(superSpeedBoots),
    "X X",
    "X X",
    'X', Item.diamond);

Now we have to copy our files (prestone_1.png and prestone2_.png) to

 forge
 \mcp
 \src
 \minecraft
 \assets
 \generic
 \textures
 \models
 \armor

prestone_2

prestone_1

And copy the inventory item images (moustachehelmet.png and superspeedboots.png) into

forge
\mcp
\src
\minecraft
\assets
\generic
\textures
\items

superspeedboots

moustachehelmet

Make sure you have a folder link to:

forge
\mcp
\src
\minecraft
\assets

That's about it! Your player can now have a moustache for a helmet, and a constant Speed III potion once the boots are equipped.

Mod: Chainsaw

This is the thirteenth lesson in a series introducing 10-year-olds to programming through Minecraft. Learn more here.

This is another suggestion from my class :)

Goal

To create a chainsaw item that can cut wood really quickly.

Relevant Classes

Item definitions extend net.minecraft.item.Item. You may recall that instances of items are created using ItemStack. Kinda sounds like classes and objects? :)

Creating A New Item

Add a new class named Chainsaw with a Superclass of net.minecraft.item.ItemAxe. Check "constructors from superclass". Update the constructor to look like this (we'll worry about the last line a bit later)

public class Chainsaw extends ItemAxe {
    public Chainsaw(int id, EnumToolMaterial material) {
        super(id, material);
        setUnlocalizedName("chainsaw");
        func_111206_d("chainsawmod:chainsaw");
    }
}

Let's say we want our chainsaw to be a faster version of an emerald axe. One way to do this is to edit EnumToolMaterial found in net.minecraft.item and add a new value like this:

MODERN(3, 2000, 200.0F, 3.0F, 10) 

... but that would make life more difficult for us later on. Luckily, there is a shortcut we can use by adding these lines to our main mod file.

import net.minecraftforge.common.EnumHelper;

public static EnumToolMaterial ModernMaterial = 
    EnumHelper.addToolMaterial(
         "MODERN", 3, 5000, 200.0F, 3.0F, 10);

You can see more details about each value in the source code; the important one is the third number, efficiencyOnProperMaterial. An emerald axe has a value of 8.0 (a gold axe has a value of 12.0, but it doesn't last as long). Ours has a value of 200! We can chop down trees pretty much instantaneously with our chainsaw...

Assigning an Icon

You'll notice that all the tools in Minecraft have a small image, or icon, that is displayed in your inventory. I've found one we can use for our chainsaw at http://findicons.com/icon/53591/chainsaw. Luckily they already have 16x16 icons with transparent backgrounds, otherwise we'd have to do some image editing in Paint.NET.

In our mod file, there is a line that looks like this

@Mod(modid="ChainsawMod", name="...", version="...")

We need to create a directory with the same name as our modid (with all lowercase letters) in {workspace}forgemcpsrcminecraftassets. Under that directory, we then create texturesitems and place our new PNG file there. For example, I have

D:\eclipse-workspace
   \forge
   \mcp
   \src
   \minecraft
   \assets
   \chainsawmod
   \textures
   \items
   \chainsaw.png

Now, remember that weird-looking third line in the constructor of our new item?

func_111206_d("chainsawmod:chainsaw");

They haven't gotten around to naming that (yet) - it should be called setItemIcon or something similar, but what it does is tell Minecraft that the icon for our item is located under the assets directory in chainsawmod and that the filename is chainsaw.png. It assumes there's a textures directory as well.

Adding the Item to the Game

In our main mod class, we can now create an instance of the Chainsaw

public static Chainsaw chainsaw = 
    new Chainsaw(5000, ModernMaterial);

and then inside load we can register it with the game

GameRegistry.registerItem(chainsaw, "Chainsaw");
LanguageRegistry.addName(chainsaw, "Chainsaw");

If you wanted to create a crafting recipe that outputs this item you could, but I just cheated and added it to the ConnectionHandler we created earlier. Here's what I see :)

chainsaw

Note: if you're using eclipse, you also need to right-click on src, Create > New Folder, Advanced, Link, and choose src/minecraft from the path above otherwise you won't see the chainsaw icon.

Sharing Your Mod

This is the twelfth lesson in a series introducing 10-year-olds to programming through Minecraft. Learn more here.

Unlike the resource mods we created earlier (text, images), our Something For Nothing mod only works when we run Minecraft through our workspace in Eclipse. What if we want to share it with our friends or upload it so others can try it out?

Prerequisites

We need to update our "real" copy of Minecraft with Forge so we can verify our mod works before distributing it. This only needs to happen once, but unfortunately when you update your version of Minecraft, you're going to have to also re-download the matching src that we did in the previous step as well as the installer mentioned below.

Visit http://files.minecraftforge.net and download the installer that matches the version you're using (we've been using 9.10.0.804). You will get a file named something like minecraftforge-installer-1.6.2-9.10.0.804.jar.

After the file downloads, double-click to run it. Verify the defaults (Install client chosen, proper directory name) and press OK.

Launch Minecraft and switch to the new profile called 'Forge'; let it copy your current username/password. Press 'Play' to satisfy yourself that it's actually working and then quit the game and launcher.

Create Your Mod Archive

  • Open Windows Explorer, navigate to your workspace directory (e.g. c:\eclipse-workspace) and then continue to forge\mcp.
  • Double-click on recompile.bat. (Don't worry if you get an error message saying "Can not find server sources")
  • Double-click on reobfuscate.bat. (Again, ignore any server-related error messages. Also ignore Windows Defender.)

You should recognize your classes in the output. For instance, I tried this after writing the "Something for Nothing" mod and got the following output

> Extracting modified classes
> New class found      : mc/jb/first/SomethingForNothing
> New class found      : mc/jb/first/ConnectionHandler
> New class found      : mc/jb/first/client/ClientProxy
> New class found      : mc/jb/first/CommonProxy

Note that the reobfuscate commands also tells you that the output has gone to the reobf subdirectory.

> Outputted mc/jb/first/SomethingForNothing     
    to reobf\minecraft 
            as mc/jb/first/SomethingForNothing.class
  • Navigate down two more directories (reobf\minecraft).
  • Select all the files/directories and ZIP them.

Try Out Your Mod

  • Copy the zip file we just created to to %appdata%\.minecraft\mods (You might have to create the mods directory if it doesn't exist)

  • Run Minecraft :)

Mod: Something For Nothing

This is the eleventh lesson in a series introducing 10-year-olds to programming through Minecraft. Learn more here.

The mod is a suggestion from my class :)

Goal

Fill crafting table with ...

  • dirt and get 64 diamonds
  • sand and get 64 emeralds
  • clay (not blocks) and get 64 obsidian

Relevant Classes

The class corresponding to items is called ItemStack and it's located in the net.minecraft.item package.

We also need to use the GameRegistry class to add our new recipe to the game. Specifically, there is a static method called addShapelessRecipe

public static void addShapelessRecipe(ItemStack output, 
                                      Object... params)

What does the ... mean? It signifies we can pass in a list of objects (items) that the user needs to put on the crafting table in order to receive the output. Because we're filling the entire table, the recipe is called shapeless (it doesn't matter which item goes in which square).

How do we do it?

We need to add the new recipe to the load method.

ItemStack diamonds = new ItemStack(Item.diamond, 64);
ItemStack dirt = new ItemStack(Block.dirt);

GameRegistry.addShapelessRecipe(
    diamonds, 
    dirt, dirt, dirt, 
    dirt, dirt, dirt, 
    dirt, dirt, dirt);

We'll also need to import net.minecraft.block.Block, net.minecraft.item.Item, and net.minecraft.item.ItemStack. Eclipse makes this easy for us: if you however on a word with a red squiggly line, you will get a popup menu with "quick fixes". Most often, the required import will be the top one and you can select it.

Now if we run the game (green play button or Ctrl+F11) and play for a little bit, we should get this:

something-for-nothing

The other two recipes are left as an exercise to the reader :)

Extra Credit

In case you want to test our your recipes without having to actually collect all the required items, you can give your player inventory items for free :)

  • Add a new class (e.g. ConnectionHandler) that implements IConnectionHandler
  • In the override for playerLoggedIn, add the following code:

    EntityPlayerMP mp = (EntityPlayerMP)player;
    mp.inventory.addItemStackToInventory(
                    new ItemStack(...));
    
  • Finally, add the following line to your mod's load event

    NetworkRegistry.instance().registerConnectionHandler(
                    new ConnectionHandler());
    

Minecraft Forge Setup

This is the tenth lesson in a series introducing 10-year-olds to programming through Minecraft. Learn more here.

Note: These instructions are only guaranteed valid for Minecraft 1.6.2 (with no mods installed) and Forge 9.10.0.804. They also assume you already have the most recent JDK installed. Fingers crossed the real API is released soon and the state of modding Minecraft will be less in flux.

Installing Forge

Instructions for installing Forge are also available at at http://www.minecraftforge.net/wiki/Installation/Source

Determine JDK version

Open a new Windows Explorer window and navigate to C:\Program Files\Java\

You will have a directory in there called jdk1.7.0_xx (depending on when exactly you installed the JDK). Double-click on it and then double-click on bin. We are going to add the full path from the explorer address bar (e.g. C:\Program Files\Java\jdk1.7.0_xx\bin) to our PATH environment variable. Leave this window open so we can copy the path later.

Add the JDK path to our PATH environment variable

  • Right-click on "Computer" and choose Properties or Windows + X and choose 'System' or open Control Panel > System and Security > System
  • Choose 'Advanced System Settings' (Windows 7: click on the 'Advanced' tab)
  • Click the 'Environment variables' button at the bottom of the tab.
  • In the "User variables for xxx" section at the top, you will see a variable called PATH.
  • Click on it and then click the Edit button.
  • Click in the "variable value" text box and then press End. The cursor should now be sitting at the end of the line, most likely after a semicolon. If there is not a semicolon at the end of the line, type one in.
  • Copy (or type in) the full path from the Explorer window we used in the first step (e.g. C:\Program Files\Java\jdk1.7.0_21\bin)
  • Press OK (and close whatever other windows we opened for this step)

Installing Minecraft Forge

  • Download the most recommended 'src' build from http://files.minecraftforge.net/
  • Extract the zip to a new directory (e.g. C:\eclipse-workspace\)
  • Open an explorer window to wherever you extracted it, double-click on forge, and then double-click on install.cmd.

Base Mod and Eclipse setup

These are a simplified version of the instructions found at at http://www.minecraftforge.net/wiki/Basic_Modding. I would suggest making a copy of the entire forge directory just in case things get messy later...

  • Make sure your workspace points to /forge/mcp/eclipse (e.g. c:\eclipse-workspace\forge\mcp\eclipse)
  • Close Task list and Outline
  • Note that you've already got 7 warnings (we just ignore them)

  • Right-click on "src", New > Package. Name = mc.{initials}.first

  • Right-click on the new package, New > Class. Name = CommonProxy. Superclass = blank. Add an empty void method to it named registerRenderers.

  • Right-click on "src", New > Package. Name = mc.{initials}.first.client

  • Right-click on the new package, New > Class. Name = ClientProxy. Superclass = CommonProxy. Change the import statement to mc.{initials}.first.CommonProxy. Add an override for registerRenderers.

  • Right-click on the original package again, New > Class. Name = Generic. Superclass = blank. Replace with the code below:

(Note - update SidedProxy with the appropriate package names)

import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import 
     cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.network.NetworkMod;

@Mod(modid="Generic", name="Generic", version="0.0.0")
@NetworkMod(clientSideRequired=true, 
            serverSideRequired=false)
public class Generic {

    // The instance of your mod that Forge uses.
    @Instance("Generic")
    public static Generic instance;

    // Says where client and server 'proxy' code is loaded.
    @SidedProxy(clientSide=
                 "mc.jb.first.client.ClientProxy",
                serverSide="mc.jb.first.CommonProxy")
    public static CommonProxy proxy;

    @EventHandler
    public void preInit(FMLPreInitializationEvent event)
    {
    }

    @EventHandler
    public void load(FMLInitializationEvent event) {
            proxy.registerRenderers();
    }

    @EventHandler
    public void postInit(FMLPostInitializationEvent event)
    {
    }
}
  • You should be able to press the green play button (or Ctrl+F11) and have Minecraft launch with your new mod available.