Ok, wanting to get save/load working, I backed up my work, then I cleaned out my MCP, and since I was doing that, I added AudioMod and DataSaver Class, as well. I also updated my MCP, and now I'm getting some of the errors others are getting.
If you to are getting these errors, it should be an easy fix. Usually it's a method call/variable name that was previously undetermined by MCP. After updating, this unknow is most likely know. Just go back to the super class (and follow the chain till you find it) and find what the new name is.
I'm guessing this would be considered an intermediate tutorial, since not many people seem to be posting how to do this. There are a few things that you will need:
1. ModLoader (a must)
2. Eclipse (inLanoche says USE ECLIPSE)
3. Techne (or a great visualization of 3 dimensional box art)
First things first. I posted else where about things I have been finding out about building mobs. I will use some of that here, and I may migrate my (continuing) findings here after this tutorial. I may also do a vid tut for those that don't want to read.
To start, I would start a new mod. Do as you will, but I say learn first, implement after. Once you understand this, it's pretty easy to do more of the basic stuff. Now to the tutorial. Please refrain from posting till I post the end of this tutorial. There are 4 Java files that need to be worked on, so I will do each one in a seperate post.
In using eclipse (since it is the only way I know how to do this, and it works well), know that your custom data files are stored in 2 places: MCP\temp\bin\minecraft\
MCP\jars\bin\minecraft.jar
so if I talk about puting a file into the mob folder, know that I mean both in the MCP\temp\bin\minecraft\mob folder and in the mod folder within the jar file MCP\jars\bin\minecraft.jar
Now on to the fun...
<sorry about the organization of this growing tutorial, it's the first I have ever made>
Updates on this tutorial:
The most important of the work here, this defines your new mob. Those that haven't seen how to add retextured biped mobs, I believe this is the only file that you need to create, and then add some code to your main Mod java file. There are things you should think about when making a new mob. What will it do? For now we'll make something passive, that wanders around and will drop something when you kill it. Later on you can look at the EntityZombie file to see how to make them burn in sunlight, or something else. Let's get started.
The first thing to note is that it extends EntityAnimal. If you don't know what this means, or the call super(), then you should look them up. It will help you to do more that what I will show you here. Getting past that, the constructor for entities will usually set the texture and the setSize.
texture calls the 64x32 png file that you will use as your texture for you mob. for now it seems it must be store in the mob folder, as shown in the string.
setSize seems to set the size of the bounding box around the mob. Not to be confused (as I was) with scaling size.
The write/readEntityToNBT methods are beyond what I know but they are needed. The next 3 "Sound" methods set the sound they will make. I have heard that you need the audioMod to be able to change them, and I have yet to play with that, so I left them alone for now. If you remove them, they mob will be silent (except for footsteps)
The next one we'll look at is the getDropItemId method. Pretty self explainatory. kill it and you "may' get the item/block id listed
protected int getDropItemId()
{
return Item.leather.shiftedIndex; //can be your own item or yourBlock.blockId
}
With the cow, there is also an interaction method, for milking if you have a bucket as your current inventory item. Take note cause you can do some fun stuff with items and other mobs if you are creative :smile.gif:. For now, we will comment that out. lets save this as our own new entity file. I use a slightly different naming convention that others so I can keep my working files together.
My main mod file will be called Mod_JWorld.java. This has to be done this way for modloader to work. But for all my other working files, I go away from ClassObjectname, such as EntityCow.java. Instead, I used the name of my mod, the object name, then the class. Do as you will, this keeps most of my files grouped together.
So today we are going to turn this cow entity into anibus! Ok, so if you are copy pasting along the way, here is my JWorld_AnibusEntity.java:
package net.minecraft.src;
public class JWorld_AnibusEntity extends EntityAnimal
{
public JWorld_AnibusEntity(World world)
{
super(world);
texture = "/mob/anibus.png";
setSize(0.9F,1.3F);
moveSpeed = 0.75F;
//yOffset *= 6F;
health = 25;
}
public void writeEntityToNBT(NBTTagCompound nbttagcompound)
{
super.writeEntityToNBT(nbttagcompound);
}
public void readEntityFromNBT(NBTTagCompound nbttagcompound)
{
super.readEntityFromNBT(nbttagcompound);
}
protected String getLivingSound()
{
return "mob.cow";
}
protected String getHurtSound()
{
return "mob.cow";
}
protected String getDeathSound()
{
return "mob.cow";
}
protected float getSoundVolume()
{
return 0.4F;
}
protected int getDropItemId()
{
return 0;
}
public boolean interact(EntityPlayer entityplayer)
{
//can use this for right click reactions
return false;
}
}
One last thing for entity that I changed above. I set the health value to 25. This is the amount of hearts this dude will have. I have also changed the variable for his moveSpeed. This takes a percentage value as a float. 0= 0% speed, 1 = 100% speed. So I have set him to 0.75 (75%) speed.
Save this file and lets move on. I will go over more methods and vars for Entities later.
Render java file
This file is used to manage the visual output of your mob. I'm fairly certain this file is not used unless you create your own model, and use the map.put command. More on that later. For now know that you can control things like size, color, render equiped items, and possilby some animation stuff.
So again, let's start with the RenderCow.java file:
Well looking at the code, it makes uses variables of EntityCow type. So basically we will replace all the EntityCow entitycow with JWorld_AnibusEntity entity. At the end of the file they type cast the entityliving passed variable with EntityCow, this too we will replace with our class, and I added one extra piece. Let's saveas and rename this file to JWorld_AnibusRender.java and make the needed changes:
So to the end of this code, I have added 2 more methods.The above methods should be left alone until you (or someone) knows more about them. I'm not there yet.
But I have added preRenderScale() and preRenderCallback. These 2 together allow us to scale our mob model. The values are the x,y and z scale values as float. Again this is a percentage, but in this case you can go over 100% to get larger mobs. This is also good for making smaller mobs, but retaining the details, instead of building a smaller model (which I have tried and is not easy).
Ok, lets move on to the more creative part, building the model.
Sorry to say that the newer versions of Techne don't have premade models, but killNature has posted a link to when you can download Techne model files of the mobs in game:
Model java file
Ok, now that we have worked out a model in Techne, let's grab the information we exported (atext.java) into a new Model file. Again, I will start with the ModelCow.java, save it as JWorld_AnibusModel.java, and clean out the exisiting data. It should look like this:
[spoiler]
package net.minecraft.src;
public class JWorld_AnibusModel extends ModelQuadruped
{
public JWorld_AnibusModel()
{
super(1, 0.0F);
[/spoiler]
Yes it's incomplete and it's missing the 2 closing "}". That's ok. We will get them from the atest.java file. Open this file up with notepad, or what ever. In the constructor (after the first "{", whcih will usually start with head.addBox(-3F, -5F, -2F, 6, 5, 4, 0F):wink.gif: copy all the lines right down to the bottom. We need to keep the super() call from the original model file, but add all the rest of the code (including some stuff after the constructor).
[/spoiler]
Now there are a few changes I have made. First off you will have to add the ModelRenderer calls for any part that you shifted the texture map. The head is usually left alone in the upper left (0,0), but I have moved the body, and the legs. So you see, for example, I have added a line in the body section:
body = new ModelRenderer(23, 0);
same for the legs (and the head is there just in case, but it's still the defualt 0,0). If you don't put these in, the defaults are used, see ModelQuadruped.java.
After the constructor, you see the render method. Keep the general formating used. every new part need to be rendered.
Next we have the setRotationAngles method. Here is were things get a bit tricky. You will notice that for the new parts I added, I have the rotation angles equal to the part it would be attached to. Now I should have rotated the ears on anibus forward a bit to give you a better idea on this, but lets say that I rotated them 20 degrees on the x axis. when you export the java, it converts it to 0.3490658F radians, and your definision for the ears would be:
[spoiler]
you negate the rotation you set for the leftear. But if you don't the ear will float in space, and not rotate with the head. BUT if you specifiy this in the setRotationAngle method:
then it will follow the head's x rotation + the 20 degrees (0.3490658F radians).
2 more things show up in the setRotationAngles method to go over. If you look at the ModelQuadruped, you will see that the body has an x rotation of 1.570796F (90 degrees). We rotated it back to 0, so I redefine that here. Last, but I don't think it should be done this way, I set the rood to renderWithRotation. This should keep all the rotations as they are defined in the constructor. Which means you can actually leave this line out. But someone creative might find a reason to use this.
Last at the bottom, we initialize our new parts. Ok the model java file is done. One last step.
Main Mod java file
Coming to the end here. So we just need to tell our mod to put this dude in game. Going back to what I talked about before, if we were just adding a new textured biped, then we could leave out the 3rd line I will be adding (map.put() call).
First, in our constructor, I call method JWorldAddMobs(); this way if I have a lot of mobs being called, I can keep them orgainized. so with this line in my constructor, I need to add these 2 methods:
public void JWorldAddMobs()
{
ModLoader.RegisterEntityID(JWorld_AnibusEntity.class, "Anibus", ModLoader.getUniqueEntityId());
ModLoader.AddSpawn(JWorld_AnibusEntity.class, 100, EnumCreatureType.creature);
}
public void AddRenderer(Map map)
{
map.put(JWorld_AnibusEntity.class, new JWorld_AnibusRender(new JWorld_AnibusModel(), 0.5F));
}
The first line in JWorldAddMobs generates an entity ID. Just like all other objects in the game, this one needs and ID.
The next line manages the spawn frequency and type. The number (in this case 100) is the frequency of finding it, or so I am told. The higher the number the more easily it will be found, though I haven't really noticed a difference once I go over 20...
last is the EnumCreatureType. this defines a bit on how/where it can spawn. Monsters spawn in dark, watercreatures spawn in water.
Last in this process is the AddRenderer method and it's map.put() call. Without this line, no matter what you have coded, you mob will appear as a biped with the default mapping co-ordinates.
ok. If you have done everything right, the game will compile, and you can start it up. If you've attempted to do something similar as to what's here, you may find this guy:
Ok, well I tried to ask about this, but no one seemed to be able to help that much. But let's say you don't want to wander around a find your mob. Well, if you know how to spawn a mob on a spot and didn't reply to my earlier request, shame on you!
in anycase, I will assume that you have done other more basic tutorials like making a block. Well you've made a block, let's do something special with it. Add this method to your block java file:
public void onBlockClicked(World world, int i, int j, int k, EntityPlayer entityplayer)
{
EntityLiving entityliving = (EntityLiving)EntityList.createEntityInWorld("Anibus", entityplayer.worldObj);
entityliving.setLocationAndAngles(i, j + 1, k, 0F, 0F); //x, y, z, yaw, pitch
entityplayer.worldObj.entityJoinedWorld(entityliving);
}
Be sure to use the same string that you gave when setting up you entityUniqueID in your main Mod java file. now, when you hit your block, POOF! You mob will appear on the block.
Sample of my block code:
package net.minecraft.src;
import java.util.Random;
// Referenced classes of package net.minecraft.src:
// Block, Material, Item
public class JWorld_SpawnerBlock extends Block
{
public JWorld_SpawnerBlock(int i, int j)
{
super(i, j, Material.sand); //allows it to be harvested by hand.
}
public int idDropped(int i, Random random)
{
return mod_JWorld.JWorld_SpawnSpot.blockID;
}
//making buildings
//can try boolean blockActivated(World world, int i, int j, int k, EntityPlayer entityplayer)
public void onBlockClicked(World world, int i, int j, int k, EntityPlayer entityplayer)
{
//i left/right (x pos)
//j up/down (y pos)
//k back/forth (z pos)
//Try to spawn above this (j/y = +1)
EntityLiving entityliving = (EntityLiving)EntityList.createEntityInWorld("Flything", entityplayer.worldObj);
entityliving.setLocationAndAngles(i, j + 1, k, 0F, 0F); //x, y, z, yaw, pitch
entityplayer.worldObj.entityJoinedWorld(entityliving);
}
}
Don't for get the stuff needed in your main mod java file,
in the constructor:
ModLoader.RegisterBlock(JWorld_SpawnSpot);
and under static{ :
JWorld_SpawnSpot = (new JWorld_SpawnerBlock(103, ModLoader.addOverride("/terrain.png", "/mods/JSpawnBlock.png"))).setHardness(0.7F).setStepSound(Block.soundSandFootstep).setBlockName("JWorld SpawnSpot");
and last the public definition:
public static final Block JWorld_SpawnSpot;
Got to this point and want to add a menu to your block to select various mobs to spawn? Spwan Block GUI
Some basic texturemaping with a techne model and photoshop.
Ok, this was asked for, so I did a quick video. This is not how to make awsome texture maps, I cannot do that. This will make it easier for you to understand and paint texture maps.
Ok, importing this stuff from one of my other threads. Here I will go over some of the things I have found about each of the 3 main java files. Most of this stuff can be found by going back through what each class extends. This is for the intermediate to, dare I say advanced modders. I'll try and give as much info as I have found. Let's start with,
Entity java file vars and methods: In the constructor: texture = string; : this is the name and location of the texture file(png file 64x32) used for this entity. May need to be stored in the mob folder. Example of use:
texture = "mob/mymob.png";
setSize(float1, float2); : Through my current tests, this seems more of the bounding box size than a scaler for the Mob. Example of use:
setSize(0.9F,1.3F) //the first number is the width, the second is the height
attackStrength = int; : The amount of damage done when hitting another mob.
attackStrength = 5;
moveSpeed = float; : This seems to be a percentage of speed. 0.1 being 10%, 1 being 100%. I have set this over 1F (to 10F), but it did not seem to make a difference. This max speed (1) is still slower than the player
This is a value that sets the speed. The player moves at a value of about 1.0F. To make a mob go faster, increase this. Slower, decrease it.
moveSpeed = 0.5F;
health = int; : The amount of health the mob will have. default is 10. I have also seen the var heartsHalvesLife, but setting this really low didn't seem to do anything, so I'm sticking with health
health = 10;
Useful Methods public void onLivingUpdate()
this method is called ever tick (or so). If you want to check things within the mob, then this is your method. If using it, you must call super.onLivingUpdate(); as it handles the movement code. Bad things happen when you overwrite this.
If you want to trigger things line waving tails, hunger, or sudden changes in behavour do it in this method. public boolean interact(EntityPlayer entityplayer)
this is called when a player right clicks on the mob. protected boolean canDespawn()
Still checking on this, but I think having this return false will keep the entity in the game. If not, and it is out of range, it has a chance of despawning. I would limit your use on this, but it is useful for pets and a number of tamed mobs.
Useful methods preRenderScale, preRenderCallback : the preRenderScale needs to be called by the preRenderCallback. I have tested this and it works. You can scale up (>1) or down(<1). i, j, k are the Float values to scale the model in it's x,y and z. You must have defined a model and used the map.put() method in your code for this to work. If you want to make several different scales of this mob, you can add another passed variable to the Render constructor (see RenderGiantZombie.java)
renderLivingLabel : This can be called to place the name over your mob. Of course you will have to create your own name var. What I did was to create a list in my entity java file, then have it select one in the constructor. It can be placed right below the first call to super.doRenderLiving(entity, d, d1, d2, f, f1); like so:
Useful methods
in the porcess of testing, but for those that may want to manage animations of body parts, I think this may help: setRotationAngles(f,f1,f2,f3,f4,f5): It would seem that the angles for the main parts of the body (head, legs, arms) is handled by adding one of the passed floats to the rotation you set in this method. (see ModelBiped, ModelQuadruped, ModelChicken, ModelGhast)
f = ?
f1 = leg/arm x axis rotations
f2 = seems to be for wing flapping/flying animation rotations on z axis
f3 = head y axis rotations
f4 = head x axis rotations
f5 = ?
For rotating objects "connected" to other parts (such as ears connected to the head) you should set the rotation points (in techne) to the same position as the part it is attached to. You can then rotate this part the same as it's "base". Please note that they are not actually attached, just rotating around the same point the same amount of rotation. If any of the parts being rotated has an inital rotation other than 0, this number needs to be added to the rotation. Eg.
head is rotatedX by 0.443F, nose is rotatedX by -1.234F then they would look like this
Building a GUI tied to your spawn block
before hand...
Ok, first off, I will have to say that optimizing my code is not the best with Java. That said, if you think I'm wasting resources and know a better way to do what I am doing, please let me know. It will only lead to better mods all round.
This may be a bit advanced, but I'm not going to show the half way and add to it. That will be messy. First thing is that I'm going to track all the mobs I create (the name ID) in a list. So in my mod_JWorld.java file I add this public static call with the other block, item, etc. delcairations:
public static final Block JBlock;
public static final Block JWorld_SpawnSpot;
public static ArrayList myMobList = new ArrayList();
The after each of my mob RegisterEntityID calls I add the name to the array list:
You could bypass this, and just build the list manually in your GUI code, but that gets messy.
Next thing is to steal some useful GUI code, let's take GuiIngameMenu.java. This has a basic menu with selectable options, and an exit out of this menu button. Open this file, then save it under a different name. I used JWorld_GUISpawner.java.
We are not going to play with the design of the menu, just muck around with the buttons and what they do. But before that, we need to update the constuctor and have it take in 4 arguments. We also have to initialize some global vars, like so:
private int spawnX;
private int spawnY;
private int spawnZ;
private World worldObj;
private Object[] tempList;
Before I go on, the tempList object is to take the list of mobs created in mod_JWorld and covert it to an array. You can probably do this other ways, but this is the way I got it to work.
public JWorld_GUISpawner(World world, int px, int py, int pz)
{
//pass the x,y and z of the spawn block being activated, so we can spawn above it
updateCounter2 = 0;
updateCounter = 0;
spawnX = px;
spawnY = py + 1; //above the block
spawnZ = pz;
worldObj = world;
}
the updateCounters are left from the original code. Leave them be for now. These 4 variables are needed to place an entity in game.
Next on to the initGui method. This defines the buttons and set's thier IDs. The ID is check when a button is pressed. I commented out thier code to keep it handy. I then copied out the "back to game" button and set it as button 0. We can then make a loop that will go through our list of mob Entity names and make buttons out of them. Following what was laid out, I put this together:
Last we need to have a reaction to a button being pressed. That's the actionPerformed method. Again, the only one I kept (and modifed to ID=0) is the button to exit the menu. Here is were all the passed args are used:
Done, for the most part. Just need to fix up the spawn block onBlockClicked (or activated-like the workbench- if that's what you did) method. Again, I left the legacy code for display purposes:
public void onBlockClicked(World world, int i, int j, int k, EntityPlayer entityplayer)
{
//i left/right (x pos)
//j up/down (y pos)
//k back/forth (z pos)
//Try to spawn above this (j/y = +1)
/* -odd spawn code. Moved to JWorld_GUISpawner.java
EntityLiving entityliving = (EntityLiving)EntityList.createEntityInWorld("Flything", world);
entityliving.setLocationAndAngles(i, j + 1, k, 0F, 0F); //x, y, z, yaw, pitch
world.entityJoinedWorld(entityliving);
*/
//call GUI
Minecraft mc = ModLoader.getMinecraftInstance();
mc.displayGuiScreen(new JWorld_GUISpawner(world, i, j, k));
}
To finish off, I will post the full code in my spawn GUI incase that was a bit broken up for some:
package net.minecraft.src;
import java.util.List;
import net.minecraft.client.Minecraft;
// Referenced classes of package net.minecraft.src:
// GuiScreen, GuiButton, StatCollector, GuiOptions,
// StatList, StatFileWriter, World, GuiMainMenu,
// GuiAchievements, GuiStats, MathHelper
// Code taken from GuiIngameMenu.java
public class JWorld_GUISpawner extends GuiScreen
{
public JWorld_GUISpawner(World world, int px, int py, int pz)
{
//pass the x,y and z of the spawn block being activated, so we can spawn above it
updateCounter2 = 0;
updateCounter = 0;
spawnX = px;
spawnY = py + 1; //above the block
spawnZ = pz;
worldObj = world;
}
public void initGui()
{
updateCounter2 = 0;
controlList.clear();
byte byte0 = -16;
/* - kept for reference.
controlList.add(new GuiButton(1, width / 2 - 100, height / 4 + 120 + byte0, "Save and quit to title"));
controlList.add(new GuiButton(4, width / 2 - 100, height / 4 + 24 + byte0, "Back to game"));
controlList.add(new GuiButton(0, width / 2 - 100, height / 4 + 96 + byte0, "Options..."));
controlList.add(new GuiButton(5, width / 2 - 100, height / 4 + 48 + byte0, 98, 20, StatCollector.translateToLocal("gui.achievements")));
controlList.add(new GuiButton(6, width / 2 + 2, height / 4 + 48 + byte0, 98, 20, StatCollector.translateToLocal("gui.stats")));
*/
controlList.add(new GuiButton(0, width / 2 - 100, height / 4 + 24 + byte0, "Back to game"));
tempList = mod_JWorld.myMobList.toArray();
for(int i = 0; i< tempList.length; i++)
{
String s = tempList[i].toString();
int j = i / 2;
if (i % 2 != 0)
{
controlList.add(new GuiButton(i+1, width / 2 + 2, height / 4 + 48 + (24*j) + byte0, 98, 20, s));
}else
{
controlList.add(new GuiButton(i+1, width / 2 - 100, height / 4 + 48 + (24*j) + byte0, 98, 20, s));
}
}
}
protected void actionPerformed(GuiButton guibutton)
{
if(guibutton.id == 0)
{
mc.displayGuiScreen(null);
mc.setIngameFocus();
return;
}
String s = tempList[guibutton.id - 1].toString();
EntityLiving entityliving = (EntityLiving)EntityList.createEntityInWorld(s, worldObj);
entityliving.setLocationAndAngles(spawnX, spawnY, spawnZ, 0F, 0F); //x, y, z, yaw, pitch
worldObj.entityJoinedWorld(entityliving);
mc.displayGuiScreen(null); //exit out after selection
mc.setIngameFocus();
}
public void updateScreen()
{
super.updateScreen();
updateCounter++;
}
public void drawScreen(int i, int j, float f)
{
drawDefaultBackground();
boolean flag = !mc.theWorld.func_650_a(updateCounter2++);
if(flag || updateCounter < 20)
{
float f1 = ((float)(updateCounter % 10) + f) / 10F;
f1 = MathHelper.sin(f1 * 3.141593F * 2.0F) * 0.2F + 0.8F;
int k = (int)(255F * f1);
drawString(fontRenderer, "Saving level..", 8, height - 16, k << 16 | k << 8 | k);
}
drawCenteredString(fontRenderer, "Game menu", width / 2, 40, 0xffffff);
super.drawScreen(i, j, f);
}
private int updateCounter2;
private int updateCounter;
private int spawnX;
private int spawnY;
private int spawnZ;
private Object[] tempList;
private World worldObj;
}
Do you know if this program has a "scale model" option? the GI scale doesn't work perfectly and does not include the rotation balls (they still use the normal grid when the model has shrunken and if I move any box alot the ball continually offsets from the box)
i think i have only two main problems 1: in my RenderMob.java on the scaling line i get a compiling error connot find symbol GL11
and the second error 2: in my ModelMob.java i get a bunch of the same compiling error connot find symbol addBox
Quite good, I liked the part of the tutorial that talked about adding to the setRotationAngles part so the horns/ears on the head would rotate with it. I did get some errors conflicting with doing that though for my model, but those are likely because of some other errors in my code though.
The scale code (using the GL11 class methods) was taken from the RenderGiantZombie code. It should work. The GL11 class is also used for color changes, and probably more. You may have forgot this line at the top of your Render code:
import org.lwjgl.opengl.GL11;
in the render java file, did you remember to define your new parts at the bottom? like
Do you know if this program has a "scale model" option? the GI scale doesn't work perfectly and does not include the rotation balls (they still use the normal grid when the model has shrunken and if I move any box alot the ball continually offsets from the box)
You mean for scaling the texture map. Unfortunately, you can't scale down beyond 1 to 1 pixel, which is what we have to work with. Still trying to track down how to use larger texture maps, it would be the only thing to help.
Thanks it all compiled correctly however theres another problem. it doesent spawn ingame or even when i try to spawn it using singleplayercommands im sorry for all the issues but i plan on making many more mobs with different qualitys so im want to learn more about them also you should have a tutorial dedicated to special item/mob/block effects like right clicking will burn something like flint and steel its just a suggestion but i would really appreciate it thanks
PLEASE NOTE:
I have begun work on my 1.8.1 tutorials. I will no longer be visiting this thread
new thread:
http://www.minecraftforum.net/topic/683263-inlanoches-tutorials-18-modloader/
Ok, wanting to get save/load working, I backed up my work, then I cleaned out my MCP, and since I was doing that, I added AudioMod and DataSaver Class, as well. I also updated my MCP, and now I'm getting some of the errors others are getting.
If you to are getting these errors, it should be an easy fix. Usually it's a method call/variable name that was previously undetermined by MCP. After updating, this unknow is most likely know. Just go back to the super class (and follow the chain till you find it) and find what the new name is.
I'm guessing this would be considered an intermediate tutorial, since not many people seem to be posting how to do this. There are a few things that you will need:
1. ModLoader (a must)
2. Eclipse (inLanoche says USE ECLIPSE)
3. Techne (or a great visualization of 3 dimensional box art)
First things first. I posted else where about things I have been finding out about building mobs. I will use some of that here, and I may migrate my (continuing) findings here after this tutorial. I may also do a vid tut for those that don't want to read.
To start, I would start a new mod. Do as you will, but I say learn first, implement after. Once you understand this, it's pretty easy to do more of the basic stuff. Now to the tutorial. Please refrain from posting till I post the end of this tutorial. There are 4 Java files that need to be worked on, so I will do each one in a seperate post.
In using eclipse (since it is the only way I know how to do this, and it works well), know that your custom data files are stored in 2 places:
MCP\temp\bin\minecraft\
MCP\jars\bin\minecraft.jar
so if I talk about puting a file into the mob folder, know that I mean both in the MCP\temp\bin\minecraft\mob folder and in the mod folder within the jar file MCP\jars\bin\minecraft.jar
Now on to the fun...
<sorry about the organization of this growing tutorial, it's the first I have ever made>
Updates on this tutorial:
-Creation of Entity, Render and Model java files
-How to use Techne to build the model
-Creating a spawn block to spawn your model
-Breakdown on the vars and Methods for Entity, Render, and Model Java files
-Adding a GUI to your block to pick what mob to spawn
-Flying mobs
-Add a name above the mob(Render java method)
- Controllable, rideable mobs (page 8, post 160, link is not working right)
- Fixing Rotation on linked objects in your Mob
- Rayvyn shows how to do Hi-Res textures
-Super/Sub Classing tip
- Custom Animations
- Keystroke Comands and Entity Control
- Texture and Model Scaling video
- Tamable Super Class example (see post for features - WIP)
- Drivable Vehicle Mob
- Creating an on screen HUD
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
The most important of the work here, this defines your new mob. Those that haven't seen how to add retextured biped mobs, I believe this is the only file that you need to create, and then add some code to your main Mod java file. There are things you should think about when making a new mob. What will it do? For now we'll make something passive, that wanders around and will drop something when you kill it. Later on you can look at the EntityZombie file to see how to make them burn in sunlight, or something else. Let's get started.
Open up EntityCow.java:
The first thing to note is that it extends EntityAnimal. If you don't know what this means, or the call super(), then you should look them up. It will help you to do more that what I will show you here. Getting past that, the constructor for entities will usually set the texture and the setSize.
texture calls the 64x32 png file that you will use as your texture for you mob. for now it seems it must be store in the mob folder, as shown in the string.
setSize seems to set the size of the bounding box around the mob. Not to be confused (as I was) with scaling size.
The write/readEntityToNBT methods are beyond what I know but they are needed. The next 3 "Sound" methods set the sound they will make. I have heard that you need the audioMod to be able to change them, and I have yet to play with that, so I left them alone for now. If you remove them, they mob will be silent (except for footsteps)
The next one we'll look at is the getDropItemId method. Pretty self explainatory. kill it and you "may' get the item/block id listed
With the cow, there is also an interaction method, for milking if you have a bucket as your current inventory item. Take note cause you can do some fun stuff with items and other mobs if you are creative :smile.gif:. For now, we will comment that out. lets save this as our own new entity file. I use a slightly different naming convention that others so I can keep my working files together.
My main mod file will be called Mod_JWorld.java. This has to be done this way for modloader to work. But for all my other working files, I go away from ClassObjectname, such as EntityCow.java. Instead, I used the name of my mod, the object name, then the class. Do as you will, this keeps most of my files grouped together.
So today we are going to turn this cow entity into anibus! Ok, so if you are copy pasting along the way, here is my JWorld_AnibusEntity.java:
One last thing for entity that I changed above. I set the health value to 25. This is the amount of hearts this dude will have. I have also changed the variable for his moveSpeed. This takes a percentage value as a float. 0= 0% speed, 1 = 100% speed. So I have set him to 0.75 (75%) speed.
Save this file and lets move on. I will go over more methods and vars for Entities later.
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
This file is used to manage the visual output of your mob. I'm fairly certain this file is not used unless you create your own model, and use the map.put command. More on that later. For now know that you can control things like size, color, render equiped items, and possilby some animation stuff.
So again, let's start with the RenderCow.java file:
Well looking at the code, it makes uses variables of EntityCow type. So basically we will replace all the EntityCow entitycow with JWorld_AnibusEntity entity. At the end of the file they type cast the entityliving passed variable with EntityCow, this too we will replace with our class, and I added one extra piece. Let's saveas and rename this file to JWorld_AnibusRender.java and make the needed changes:
So to the end of this code, I have added 2 more methods.The above methods should be left alone until you (or someone) knows more about them. I'm not there yet.
But I have added preRenderScale() and preRenderCallback. These 2 together allow us to scale our mob model. The values are the x,y and z scale values as float. Again this is a percentage, but in this case you can go over 100% to get larger mobs. This is also good for making smaller mobs, but retaining the details, instead of building a smaller model (which I have tried and is not easy).
Ok, lets move on to the more creative part, building the model.
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
Sorry to say that the newer versions of Techne don't have premade models, but killNature has posted a link to when you can download Techne model files of the mobs in game:
Part 1
Part 2
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
Ok, now that we have worked out a model in Techne, let's grab the information we exported (atext.java) into a new Model file. Again, I will start with the ModelCow.java, save it as JWorld_AnibusModel.java, and clean out the exisiting data. It should look like this:
[spoiler] [/spoiler]
Yes it's incomplete and it's missing the 2 closing "}". That's ok. We will get them from the atest.java file. Open this file up with notepad, or what ever. In the constructor (after the first "{", whcih will usually start with head.addBox(-3F, -5F, -2F, 6, 5, 4, 0F):wink.gif: copy all the lines right down to the bottom. We need to keep the super() call from the original model file, but add all the rest of the code (including some stuff after the constructor).
It should look something like this:
[spoiler] [/spoiler]
Now there are a few changes I have made. First off you will have to add the ModelRenderer calls for any part that you shifted the texture map. The head is usually left alone in the upper left (0,0), but I have moved the body, and the legs. So you see, for example, I have added a line in the body section:
same for the legs (and the head is there just in case, but it's still the defualt 0,0). If you don't put these in, the defaults are used, see ModelQuadruped.java.
After the constructor, you see the render method. Keep the general formating used. every new part need to be rendered.
Next we have the setRotationAngles method. Here is were things get a bit tricky. You will notice that for the new parts I added, I have the rotation angles equal to the part it would be attached to. Now I should have rotated the ears on anibus forward a bit to give you a better idea on this, but lets say that I rotated them 20 degrees on the x axis. when you export the java, it converts it to 0.3490658F radians, and your definision for the ears would be:
[spoiler]
[spoiler]
unfortunately when you add the line :
you negate the rotation you set for the leftear. But if you don't the ear will float in space, and not rotate with the head. BUT if you specifiy this in the setRotationAngle method:
then it will follow the head's x rotation + the 20 degrees (0.3490658F radians).
2 more things show up in the setRotationAngles method to go over. If you look at the ModelQuadruped, you will see that the body has an x rotation of 1.570796F (90 degrees). We rotated it back to 0, so I redefine that here. Last, but I don't think it should be done this way, I set the rood to renderWithRotation. This should keep all the rotations as they are defined in the constructor. Which means you can actually leave this line out. But someone creative might find a reason to use this.
Last at the bottom, we initialize our new parts. Ok the model java file is done. One last step.
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
Coming to the end here. So we just need to tell our mod to put this dude in game. Going back to what I talked about before, if we were just adding a new textured biped, then we could leave out the 3rd line I will be adding (map.put() call).
First, in our constructor, I call method JWorldAddMobs(); this way if I have a lot of mobs being called, I can keep them orgainized. so with this line in my constructor, I need to add these 2 methods:
The first line in JWorldAddMobs generates an entity ID. Just like all other objects in the game, this one needs and ID.
The next line manages the spawn frequency and type. The number (in this case 100) is the frequency of finding it, or so I am told. The higher the number the more easily it will be found, though I haven't really noticed a difference once I go over 20...
last is the EnumCreatureType. this defines a bit on how/where it can spawn. Monsters spawn in dark, watercreatures spawn in water.
Last in this process is the AddRenderer method and it's map.put() call. Without this line, no matter what you have coded, you mob will appear as a biped with the default mapping co-ordinates.
ok. If you have done everything right, the game will compile, and you can start it up. If you've attempted to do something similar as to what's here, you may find this guy:
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
Updated with FULL sample code:
Ok, well I tried to ask about this, but no one seemed to be able to help that much. But let's say you don't want to wander around a find your mob. Well, if you know how to spawn a mob on a spot and didn't reply to my earlier request, shame on you!
in anycase, I will assume that you have done other more basic tutorials like making a block. Well you've made a block, let's do something special with it. Add this method to your block java file:
Be sure to use the same string that you gave when setting up you entityUniqueID in your main Mod java file. now, when you hit your block, POOF! You mob will appear on the block.
Sample of my block code:
Don't for get the stuff needed in your main mod java file,
in the constructor:
and under static{ :
and last the public definition:
Got to this point and want to add a menu to your block to select various mobs to spawn?
Spwan Block GUI
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
Ok, this was asked for, so I did a quick video. This is not how to make awsome texture maps, I cannot do that. This will make it easier for you to understand and paint texture maps.
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
Entity java file vars and methods:
In the constructor:
texture = string; : this is the name and location of the texture file(png file 64x32) used for this entity. May need to be stored in the mob folder. Example of use:
setSize(float1, float2); : Through my current tests, this seems more of the bounding box size than a scaler for the Mob. Example of use:
attackStrength = int; : The amount of damage done when hitting another mob.
moveSpeed = float; :
This seems to be a percentage of speed. 0.1 being 10%, 1 being 100%. I have set this over 1F (to 10F), but it did not seem to make a difference. This max speed (1) is still slower than the playerThis is a value that sets the speed. The player moves at a value of about 1.0F. To make a mob go faster, increase this. Slower, decrease it.
health = int; : The amount of health the mob will have. default is 10. I have also seen the var heartsHalvesLife, but setting this really low didn't seem to do anything, so I'm sticking with health
Useful Methods
public void onLivingUpdate()
this method is called ever tick (or so). If you want to check things within the mob, then this is your method. If using it, you must call super.onLivingUpdate(); as it handles the movement code. Bad things happen when you overwrite this.
If you want to trigger things line waving tails, hunger, or sudden changes in behavour do it in this method.
public boolean interact(EntityPlayer entityplayer)
this is called when a player right clicks on the mob.
protected boolean canDespawn()
Still checking on this, but I think having this return false will keep the entity in the game. If not, and it is out of range, it has a chance of despawning. I would limit your use on this, but it is useful for pets and a number of tamed mobs.
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
in the constructor
Useful methods
preRenderScale, preRenderCallback : the preRenderScale needs to be called by the preRenderCallback. I have tested this and it works. You can scale up (>1) or down(<1). i, j, k are the Float values to scale the model in it's x,y and z. You must have defined a model and used the map.put() method in your code for this to work. If you want to make several different scales of this mob, you can add another passed variable to the Render constructor (see RenderGiantZombie.java)
renderLivingLabel : This can be called to place the name over your mob. Of course you will have to create your own name var. What I did was to create a list in my entity java file, then have it select one in the constructor. It can be placed right below the first call to super.doRenderLiving(entity, d, d1, d2, f, f1); like so:
the var myName was created by me in my entity class (JWorld_FlythingEntity). This can be any String value.
<more to come>
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
in the constructor
Useful methods
in the porcess of testing, but for those that may want to manage animations of body parts, I think this may help:
setRotationAngles(f,f1,f2,f3,f4,f5): It would seem that the angles for the main parts of the body (head, legs, arms) is handled by adding one of the passed floats to the rotation you set in this method. (see ModelBiped, ModelQuadruped, ModelChicken, ModelGhast)
f = ?
f1 = leg/arm x axis rotations
f2 = seems to be for wing flapping/flying animation rotations on z axis
f3 = head y axis rotations
f4 = head x axis rotations
f5 = ?
For rotating objects "connected" to other parts (such as ears connected to the head) you should set the rotation points (in techne) to the same position as the part it is attached to. You can then rotate this part the same as it's "base". Please note that they are not actually attached, just rotating around the same point the same amount of rotation. If any of the parts being rotated has an inital rotation other than 0, this number needs to be added to the rotation. Eg.
head is rotatedX by 0.443F, nose is rotatedX by -1.234F then they would look like this
head.rotateAngleX = (f4 / 57.29578F) + 0.443F;
nose.rotateAngleX = (f4 / 57.29578F) - 1.234F;
This would keep their start rotation angle, and add the rotation from the game engine to it, keeping them in sync.
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
before hand...
Ok, first off, I will have to say that optimizing my code is not the best with Java. That said, if you think I'm wasting resources and know a better way to do what I am doing, please let me know. It will only lead to better mods all round.
This may be a bit advanced, but I'm not going to show the half way and add to it. That will be messy. First thing is that I'm going to track all the mobs I create (the name ID) in a list. So in my mod_JWorld.java file I add this public static call with the other block, item, etc. delcairations:
The after each of my mob RegisterEntityID calls I add the name to the array list:
You could bypass this, and just build the list manually in your GUI code, but that gets messy.
Next thing is to steal some useful GUI code, let's take GuiIngameMenu.java. This has a basic menu with selectable options, and an exit out of this menu button. Open this file, then save it under a different name. I used JWorld_GUISpawner.java.
We are not going to play with the design of the menu, just muck around with the buttons and what they do. But before that, we need to update the constuctor and have it take in 4 arguments. We also have to initialize some global vars, like so:
Before I go on, the tempList object is to take the list of mobs created in mod_JWorld and covert it to an array. You can probably do this other ways, but this is the way I got it to work.
the updateCounters are left from the original code. Leave them be for now. These 4 variables are needed to place an entity in game.
Next on to the initGui method. This defines the buttons and set's thier IDs. The ID is check when a button is pressed. I commented out thier code to keep it handy. I then copied out the "back to game" button and set it as button 0. We can then make a loop that will go through our list of mob Entity names and make buttons out of them. Following what was laid out, I put this together:
Last we need to have a reaction to a button being pressed. That's the actionPerformed method. Again, the only one I kept (and modifed to ID=0) is the button to exit the menu. Here is were all the passed args are used:
Done, for the most part. Just need to fix up the spawn block onBlockClicked (or activated-like the workbench- if that's what you did) method. Again, I left the legacy code for display purposes:
To finish off, I will post the full code in my spawn GUI incase that was a bit broken up for some:
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
Check out my Minecraft Modding Tutorials!
and the second error 2: in my ModelMob.java i get a bunch of the same compiling error connot find symbol addBox
The scale code (using the GL11 class methods) was taken from the RenderGiantZombie code. It should work. The GL11 class is also used for color changes, and probably more. You may have forgot this line at the top of your Render code:
in the render java file, did you remember to define your new parts at the bottom? like
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE
You mean for scaling the texture map. Unfortunately, you can't scale down beyond 1 to 1 pixel, which is what we have to work with. Still trying to track down how to use larger texture maps, it would be the only thing to help.
OLD 1.7: http://www.minecraftforum.net/topic/529327-modloader173-adding-custom-mobs-and-more/ ---inLanoche says : USE ECLIPSE