Hello! And thank you for your interest in modding, you crazy thang. If you're looking for a general explanation or introduction to the Minecraft source code so that you can do some very in-depth modding, you've come to the right place. I'm mostly writing this with the intention of it being a handy modding reference one day, so if you're looking for something specific (and I mean specific), it may very well be here in the future. If you're making something like a full-fledged Pokemon mod, an entirely new in-game GUI, a rogue-like dungeon generator, or even... THE ELUSIVE DRAGON MOD (God help us all), this is the guide for you! For this in-depth modding guide, I'm going to assume the following...
Prerequisites For This Guide
You are familiar with an Object-Oriented C-like language (since that's what Java, the language Minecraft was programmed in, happens to be). I'm not teaching any basic programming skills, but I WILL fling you face-first into Java if you've got some programming foundation. It's real easy if you're starting from C++, C#, etc.
You've already installed MCP and all it's prerequisites, along with a working Eclipse project, and you've confirmed that everything's working. There are plenty of great tutorials on the forums, so please don't bother me about it.
You're both patient and a good learner.
You probably ought to be familiar with the concept of binary and hex.
You luuuurrrve yourself some Minecraft and are full of fantastic, wonderful ideas.
NOTE: This is a guide primarily for those interested in advanced modding. I'm not going to assume that you're using ModLoader or any other modding API because, if you're mod is particularly expansive and/or innovative, there may not be an API like Modloader flexible enough to do what you want. That's why Notch announced there wouldn't be an official Modding API, simply because you could never make an API good enough to do everything you'd want it to. Instead, they're releasing the source code! So, if you can pull it off with Modloader, great, you should do that! Your mod will integrate seamlessly with other ModLoader mods, which you should strive for if possible. Otherwise, don't fret, because I'm not going to assume that you're using it. I may cover ModLoader later, but I'm currently avoiding it myself because my mod is too crazy to work with it (I shall reveal it to the world soon... hehe). The point is, don't expect your mod to work seamlessly with other mods without ModLoader There is a javadoc that comes with ModLoader should you choose to use it, as well as a fine collection of tutorials on the forums. This guide may still prove helpful to you even if you use ModLoader, so read on!
I really want to stress that this is NOT a compilation of tutorials, but rather, a guide and a reference for modding. There will be an occasional example you can follow, but I encourage you to experiment with them, rather than follow them exactly. I will stress details like crazy so that YOU can be a better modder, so if you're looking for something quick and dirty, you might be disappointed. If you want to make a fabulous mod, however, then read on! If you need help with something specific (once this guide has some bulk), try searching the thread for it! There are already some good tutorial compilations out there, actually, but I wanted to take it a step further than that. I don't want to guide you step by step on how to do something specifically, I want you to be well equipped to do whatever you can imagine! I want you to be both self-sufficient and capable of doing whatever your brain can come up with. So, in the process of reading this guide, you should acquire a strong understanding of how the Minecraft source is organized, some good programming practices, how to modify many of the existing Minecraft classes (make new items, block, creatures, recipes, game mechanics, you name it!), how to work a bit with OpenGL, and really start thinking outside the box.
If you want to contribute, make suggestions, etc:
Hmm... this is probably gonna be more like a textbook than a guide XD If you're already a very experienced modder, you may still find some of this information useful, and I may very well find some of YOURS useful if you feel like contributing! Send me a PM if you're up to writing something (or already have something written) and I'll probably edit it and stick it on here with your name branded at the top. If it's something along the lines of a tutorial, please make sure it communicates something generally useful, otherwise I won't add it. The tutorial should be more along the lines of an example of something you're talking about. Describe things broadly, make things generalizable, and do so in the spirit of giving the reader tools that can be widely applied (details on how the Minecraft engine works, etc). Also, PM any suggestions, corrections, or useful additions, I ain't always right. I strive to be perfect! PERFECT!!! I'll definitely try to keep updating this, but feedback certainly keeps me motivated!
Overview
In this first post I'm gonna be talking about some Java specifics and how it ties into Minecraft, along with ways to show the garbage-collector some love since the GC is currently a huge problem for Minecraft. You'll also learn about bitwise operations! Hopefully you'll both get the hang of Java and get to where you can begin experimenting with modding in the process! If you're a Java expert/guru who knows many of the inner-workings of the compiler, you probably won't need to read this one (actually, you could probably just open up the project and start experimenting and come back later once you've had some fun). Otherwise, here's a couple of things you should know about Java...
Some Details About Java
How Java Works
Java exists in a sweet gray spot between compiled and interpreted languages. It is compiled into what is known as "byte code," which you can think of as a version of your code that's been optimized by the compiler and reduced to a much simpler set of instructions (and thus a much fatter/faster set of instructions). The byte code is then interpreted by the Java Virtual Machine (JVM) at run-time, which means Java relies on another executable to carry out it's instructions, instead of being compiled into an executable itself. This byte code is practically platform independent, because it can run any platform that supports the JVM (a lot of platforms). The JVM's what you always have to install on your computer before you can use Java for the first time... good to know, right?
Note that Java is only as platform independent as the JVM is. So while you're code may technically run on any platform with the JVM, that doesn't mean that the JVM for that platform is any good... that's the main reason Minecraft doesn't run well on a Mac! It runs fine on my MacBook Pro, but that's because I paid $3000 for it... *facepalm* So Oracle may claim that Java is platform independent, but I say take nothing at face value
Java is Garbage Collected
Java is a garbage-collected object-oriented language with a C-like syntax. Remember all that memory-management you might have been doing in C++ or Objective-C? You don't gots to do it no more! You never have to explicitly deallocate memory. Iow, no more...
The Java garbage collector automagically manages memory for you, giving you extreme convenience at the price of run-time performance. Normally, this is of little consequence, but in a real-time application like Minecraft, you wind up getting major lag spikes or "hiccups" as you play. This is because the GC periodically checks if you are short on memory, then sweeps through all the memory in your program to free up any memory that isn't currently in use... THIS TAKES FOREVER, but is the price Mojang pays for using Java. It's great for us though, because Java is relatively easy to decompile, meaning we get to gank the source code (legally in this case) and make mods!
Java is a C-Like Language
Did I mention that Java is a C-like language? This means that Java is considered to have a similar syntax as plain ol' C. In both C and Java (along with objC, C++, and C#), this is a valid code fragment:
int result = 1;
for (int i = 7; i > 1; --i)
{
result *= i;
}
//We just dun' calculated a factorial!!!
Order of operations is basically the same among every widely used C-like language. Like C, the use of assignment statements in expressions is valid in Java, but they have a lower precedence than most everything else. So the following two "if" statements are very different:
int var;
if (var = 3 + 5 > 2)
{
//Because 3 + 5 > 2 is always true, and "=" has very low precedence,
//we just tried to assign "true" into var, which is a compile-time error... d'oh!
//This is because Java distinguishes strictly between Integer types and Boolean types...
//in other C-like languages, this would compile, "true" basically equating to "1."
}
if ((var = 3) + 5 > 2)
{
//We just assigned "3" into var, then evaluated the expression as though we had
//just said "3" instead of "var = 3".
}
//We're so hardcore our code doesn't have to be LEGIBLE!!! MUAHAHAHAH!!!
//Never do this kinda thing unless absolutely necessary for efficiency's sake.
Java has the incremental operators (++,--) and all the compound assignment operators included in C (+=,-=,*=,/=), along with all the regular mathematical operators, so you should be feeling pretty comfortable with the syntax by now.
How Java Treats Variables
Java uses what is known as a "reference model" for classes. This means that you cannot instantiate a class on the stack (as possible in C++ or with structs in C#. This is called using a "value model"). Classes are always allocated on the heap. Observe!
//C++ and the Stack
MyClass var;
var.SomeField = 42;
var.AnArray[0] = 27;
//C++ and the Heap ('new' and 'delete')
MyClass* var = new MyClass();
var->SomeField = 42;
(*var->AnArrayPointer)[0] = 27;
delete var;
//Java and the Heap (just 'new', there's no 'delete' thanks to the GC!)
MyClass var = new MyClass();
var.SomeField = 42;
var.AnArrayPointer[0] = 27;
//Java and the Stack
//Can't do it. Sorry, bub.
While in C and C++ you must use the '*' or '->' operators to explicitly dereference pointers, in Java there is no such thing as "dereferencing" a pointer; classes are always allocated on the heap, so dereferencing is assumed! The same is true for classes in C#, whereas structs in C# are assumed to be allocated on the stack. Java has no structs, but primitives (int, float, char, long, etc) in both Java and C# are allocated on the stack.
REMEMBER: value model == allocated on the stack, reference model == allocated on the heap. Classes in Java use a reference model, primitives use a value model.
Classes in Java
In Java, every class must have at least one constructor. If you don't define any, the default constructor is implicitly defined for you (one that does nothing and accepts no parameters). This is identical to the way C++ and C# handle constructors. Because you're not responsible for any memory management in Java (thanks to the garbage collector), there is no destructor in Java.
Something strange and magical happens before the constructor is called in Java... check this out:
class MyClass
{
public MyClass()
{
}
int i = 0;
float f = 3.0F;
}
Wtf? This may look crazy at first, but this is one of my favorite parts about Java (and C#). Right before the constructor is executed, all the initialization statements declared outside of a method fire, meaning you may not even need to define a constructor! Furthermore, fields and methods may be declared in any order and reference each other freely- there is no need to prototype anything within a class! This allows you to organize methods and fields according to how they relate, giving you more modularity and less conceptual strain while programming! Unfortunately, the decompiled Minecraft code is not organized as Mojang programmed it- all fields have been pushed to the bottom of the class and methods have been pushed to the top. If you're adding functionality to any existing classes in the game, I recommend placing your new methods and fields right next to eachother at the very bottom of the class. This is especially convenient if you're copy-pasting from an old version of Minecraft to a new one (at least if you're doing it manually I believe there are automatic updating tools, but I'm not sure how much work they actually save you. It took me about a day to copy-paste a massive project from 1.4 to 1.5, hehe, but even if you auto-updated you'd have to run through and make sure your code is working properly, so you might as well have it organized)
Interestingly, Java enforces a 1:1 relationship between classes and the .java files that contain them. This means that EVERYTHING must belong to a class or an interface (even the "main" function!)... however, classes may contain other classes. Additionally, classes may only inherit from one other class in the traditional sense ("single-inheritance"), but blurs the line a bit with interfaces...
Interfaces
A class can have as many interfaces as you want. Interfaces are comparable to the following:
Interfaces in C# (they're almost identical)
In C++, a class with no fields and only pure virtual methods
Protocols in Objective-C
An interface could be thought of as a class with no fields and a bunch of prototype (declared but undefined) methods. By implementing an Interface, your class assumes the responsibility of defining the Interface's methods, or it'll be a compile-time error (unless your class is abstract, in which case, any classes inheriting from the abstract class must define the Interface's methods. Iow, you can't have a concrete class with unimplemented methods!). You should think of the Interface as a contract you have agreed to fulfill, NOT like a superclass in the traditional object-oriented sense. It's not really a rectangle-square relationship, it's more of a contract-signer one. You'll get it eventually, no worries.
Here's what some typical class declarations might look like:
class Polygon implements IArea, IPerimeter
{
//You'd define the method declarations of IArea and IPerimeter here
}
class Quadrilateral extends Polygon
{
}
interface IDrawable
{
public void DrawDisThang();
}
class GameSprite extends Quadrilateral implements IDrawable
{
public void DrawDisThang()
{
//Handle drawing!
}
}
Alright, let's have a look here. "Gamesprite" is a class we are declaring, which is a subclass of "Quadrilateral" ("extends" is the keyword for traditional subclassing) and has the interface "IDrawable" ("implements" is the keyword for declaring Interfaces). Firstly, look at the syntax of "DrawDisThang"s declaration and definition (in the interface and class, respectively)- they are the same except that the declaration terminates with a semi-colon, whereas the definition terminates with the method body (just like a regular method). Easy peasy. Secondly, notice the naming convention for Interfaces- it's generally a good idea to prefix your interfaces with "I", otherwise it might start getting confusing (it's your decision, though). Thirdly, notice that "Polygon" has multiple Interfaces and only one superclass. Remember, you can have as many interfaces as you want, but only one direct superclass (a class's superclass's superclass is still considered to be a superclass of the lowest level class, though, just not directly. You can picture single-inheritance as an upside-down tree with the highest level class at the top, and it's subclasses forming the branches underneath it. Each and every subclass inherits the methods and fields of the superclass above it, meaning EVERY subclass inherits from the highest level superclass. You'll see this quite often in Java, and Minecraft is no certainly no exception).
It's always hard to come up with understandable examples for polymorphism (I've never seen one I liked), but you'll get it when you start working with the code. You never really think of a class as "the class, it's superclass, and ALL of its interfaces" at any point in time, you just think about the class itself and are aware of the additional things, only thinking about them in detail when necessary (reduction of conceptual strain is one of the reasons polymorphism exists!) Besides, Eclipse makes jumping to a method declaration in a superclass as easy as right clicking the method call then selecting "Jump to Definition."
Methods and Fields in Java
Methods are very similar to what you would find in C#. The grammar for a method declaration looks like this: <keyword list> <return type> <methodID> '(' <parameter list> ')' '{' <method body> '}'. The grammar for a method call looks like this: <class instance> '.' <methodID> '(' <parameter list> ')'. Here are some examples:
class MyClass
{
public int number;
public MyClass()
{
number = this.MyMethod(2);
//number is now 4!
}
public int MyMethod(int param)
{
return param*2;
}
}
You should already be familiar with the concepts of "public," "protected," and "private" if you know a C-like OO language (objC doesn't technically have "private" methods because objC is retarded, but you'll be alright). A class's "public" fields/methods are accessible to everyone, whereas "protected" ones are accessible only to the class and its subclasses. "Private" methods/fields are accessible only to that class, NOT its subclasses. A good rule of thumb if you're uncertain is to start out "private" and increase visibility as necessary- this is especially nice for code completion (frequently called "Intellisense" in Eclipse, brought up with Ctrl+Space as your typing) so you won't have to choose among a whole bunch of fields and methods you don't need.
Static methods/fields are those declared on the class itself, as opposed to being on an instance of the class. This is done using the "static" keyword. Instances of a class can access static methods/fields freely, but static methods cannot directly access instance methods/fields; if you wanted that, you'd have to devise something fancy, which I'll show you in a bit!
The "final" keyword is basically the same as "const" in C, C++, and objC. It means that once something has been assigned to it, it can never be assigned to again. The compiler must be able to confirm that it will only happen only once, so declaring a "final" variable then assigning to it in a "for" loop you know will only iterate once ain't good enough!
In general, if you're programming for efficiency, you should try to define things as "static final" fields whenever possible. Why? The compiler basically just replaces every use of the field with the value you assigned to it, both reducing processing time and moving memory consumption from RAM to system memory! In terms of efficiency, doing things statically is the way to go.
Here's a neat example for ya (very similar to what you'll be seeing in several Minecraft classes, actually):
class MyClass
{
protected int ID;
public static long instanceCount = 0;
private static final long maximumInstanceCount = 5;
public static List instances = new List();
public static MyClass a;
public static MyClass b;
public static MyClass c;
public static MyClass d;
public static MyClass e;
static
{
//Isn't this cool? This code executes at the very beginning of the program
a = new MyClass(0);
b = new MyClass(1);
c = new MyClass(2);
d = new MyClass(3);
e = new MyClass(4);
}
public MyClass(int id)
{
this.ID = id;
++instanceCount;
if (instanceCount > maximumInstanceCount)
System.out.println("You made too many MyClasses, stupid!");
instances.add(this);
}
}
Hopefully that helped you understand how you can tie building blocks as simple as visibility, "static," and "final" together to do some very interesting things. You'll see a format very similar to this in the Item and Block classes. Additionally, several classes (ie CraftingManager) define a single public instance statically using a private constructor, ensuring that only one instance exists throughout the life of the program. Cool beans.
Speeding up your Mod and Helping the Garbage Collector
(This is only really necessary if your mod takes up a lot of processing power (ie a radar, a new creature with a ton of things happening with every game tick, a complex new gui, etc) or is otherwise core engine related)
Here's a few general things you can do to ensure your mod is running efficiently:
You're code should be reduced to as few instructions as possible (duh)
Your algorithms should have as low a polynomial time as possible (Don't use a triple-nested for loop to iterate through a 1,000 blocks... that's 1,000,000,000 iterations... *facepalm*)
Instead of allocating variables with each iteration of a loop, try allocating them just beforehand, then reuse them with each iteration (ESPECIALLY if they're allocated on the Heap! The GC will thank you.)
Division of doubles/floats has a TON of overhead when compared with multiplication! Don't divide if you can multiply!
Avoid calculating square roots and trigonometric functions as much as humanly possible! These functions are approximations, which take FOREVER. Instead of saying "Math.sqrt(length*length+height*height) > distance", say "length*length+height*height > distance*distance." If you're calculating distance frequently, this will save you a MASSIVE amount of time.
Appending Strings with the '+' operator seems harmless enough, but appending more than two things in a row involves a ton of unnecessary copying. Instead, use the StringBuilder class! Instead of, "My favorite " + "number is " + number), you'll have, new StringBuilder().append("My favorite ").append("number is ").append(number).toString()
Make sure you're passing around as few variables as possible between your methods. Passing in an Array with 10 entries is faster than passing in 10 variables (since you're only passing in an Array pointer).
Try consolidating a behavior into as few methods as possible- method calls take a relatively long time. Though Java will automatically inline static, private, or final methods when it can, it's generally more reliable to inline things yourself. Basically, you're sacrificing legibility/modularity for efficiency.
Be careful when deciding on whether to use classes or primitives- referring to "var.number" takes longer than just "number," but passing "var" to a method is faster than passing all of its fields. Choosing between 3 static Arrays with 100 primitives each or a static Array with 100 entries, each a class with 3 fields, could make a huge difference in run time; however, figuring out which works better may take some thought and experimentation. It depends on how you're using it!
If a method is getting called all the time, try allocating some of its variables statically. (If they're allocated on the Heap, the GC will thank you once again.) If you can reduce them to "static final" variables, you'll save MAJORLY on efficiency (as I've explained once before!)
Read the following paragraph!
Unfortunately with Java, since you cannot EXPLICITLY instantiate a class on the stack (Java uses a "reference model" for classes), every method/field on a class has an extra level of indirection; you must go through a pointer to get to them, which ultimately makes Java a bit slower from the get-go (in addition to the fact that anything allocated on the heap must be garbage collected *facepalm*). HOWEVER, the compiler can sometimes deduce that a class instance will not be used anywhere else in the program, and can therefore (unbeknownst to you) allocate it on the stack to both reduce garbage collection and remove that extra level of indirection. This is only the case if the compiler can guarantee you created the class instance in a method and never passed it out to anything else (you never returned it, passed it to another method call, assigned it to another variable's field, assigned it to a static field, etc). If you're doing anything processor intensive in your mod and you need a little extra grease (ie your mod draws a live radar with OpenGL calls, your mod regularly updates some hossly cellular-automata, etc), then bear this in mind so that you don't make the garbage-collector any slower in Minecraft than it has to be! The GC is already doing the best it can, give the poor thing a rest! Don't make Minecraft "hiccup" any more than it already does or no one will want to play your mod (and remember that those hiccups are probably gonna get worse as Mojang develops the game, so "running good enough" today may be "barely running at all" tomorrow.)
Bitwise Operations (If you're doing anything with Chunks, OpenGL, color, or the general core engine of Minecraft, read this!!!)
The Basics
Of particular importance are the bitwise operators! Minecraft makes gratuitous use of them. They are &, |, ^, ~, <<, >>, and >>>. The following statements all assign '5' into 'var':
int var;
var = 5;
var = 0x5; //"0x" denotes hex in Java. I don't believe there is a way to denote binary
//in Java, but hex is more legible anyways. Note that every 4 bits of a
//binary number can be compounded into a hex number, and vice-versa. So 0xF5
//would expand into 1111 0101, 0x32 would be 0011 0010, etc.
var = 0xF & 0x5; //In binary: 1111 & 0101 == 0101. We just "ANDed" every bit of the two numbers
var = 0x4 | 0x1; //In binary: 0100 | 0001 == 0101. We just "ORed" every bit in this case
var = 0x6 ^ 0x3; //In binary: 0110 ^ 0011 == 0101. We just "EXORed" every bit here, which
//I'll explain in a moment
var = ~0xA; //In binary: ~1010 == 0101. We just "complemented" the number, or
//"flipped the bits".
Those are the most basic bit operations you'll be seeing around the place. Note that '&'ing a variable is often referred to as "masking" it, since it is frequently used to hide bits you don't care about, which you'd probably be doing if you were working with OpenGL. EXOR is different from OR in that EXOR only returns "true" when the two bits are different. That is, 1^0 == 0^1 == 1, whereas 0^0 == 1^1 == 0. Interestingly, 0x5 ^ 0xF == ~0x5, whereas 0x5 ^ 0x0 == 0x5, so the former is a complement and the latter is redundant. NOTE: Engineers would refer to "flipping the bits" as a "one's complement." A "two's complement" is when you flip the bits then add 1, which is significant because it may affect the format of the numbers you're working with. Anyways, NOW YOU KNOW!
Bitshifts
This part may be useful if you're working with OpenGL or Chunks... the following statements all assign "6" into "var":
var = 0x3 << 1; //In binary: 0011 << 1 == 0110. This is called a "left bit shift," which
//basically just pushes however many '0' bits you specify on the
//right-hand-side of the number. Note that while this normally multiples the
//number by 2 to the <number of zeroes>, it is possible to push bits off the
//left-hand-side, so be wary of however many bits your variable can hold.
//"short"s typically hold 2 bytes, "int"s typically hold 4 bytes, "long"s
//usually hold 8 bytes.
var = 0xC >>> 1; //In binary: 1100 >>> 1 == 0110. This is called a "logical right bit shift,"
//which is practically the same as the left bit shift but towards the right.
//It pushes '0' bits on the left-hand-size and removes bits on the right.
//It does NOT, however, technically divide the number by a power of two
//unless it is an unsigned number. That is what the following bit-shift is for...
var = 0x0C >> 1; //In binary: 0000 1100 >> 1 == 0000 0110. This is called an "arithmetic
//right bit shift," which works the same as the logical one EXCEPT that
//it duplicates the leftmost bit as opposed to just inserting '0', thus
//preserving the variable's negative or positive state. This is mostly
//useful for dividing by a power of 2, but for modding purposes you probably
//won't need it, though you should DEFINITELY know not to use ">>"
//when you really meant ">>>" (which you may very well be using).
If you're working with OpenGL at all, the bit-shifts are useful for grabbing color channels out of a color represented by an int. So let's say you've got purple represented in RBGA (0xFF00FFFF) and you wanna grab the B channel. Just say "byte var = (purple >>> 8) & 0xFF" and you've got that channel! For colors, use ">>>", NOT ">>", or it'll wind up screwing you over some day.
WOW that was technical. Let's take a break. Go grab some coffee and meet me again later, then we shall dance the dance of the modder... But before then, you should be sure to at least look around the Eclipse project, particularly the Items class, make some fun little changes, recompile, and see what happens! I personally prefer the stackable Wooden Sword of Over 9000 damage, but that's just me.
You get to make your first test mod! Are you excited? You should be. I'm going to teach you some good ways to navigate the Minecraft projects using Eclipse.
Similarities Between Client and Server
Alright, go ahead and pull up the workspace in Eclipse. Before we begin looking at the code, notice that you have two projects- "minecraft" and "minecraft_server." The first is the client side, the second is the server side. Open them both up. Notice how many of the same classes appear in both projects? If you were to open one up, you'd notice that, apart from the gibberishy, decompiled method/field names, these projects are 95% identical! This is because Mojang basically had one body of files that was cross-referenced between two seperately compiled projects. If a method or class wasn't referenced by a project, it wasn't compiled into it! That's why the decompiled client side you're looking at has a bunch of "Renderer" classes that aren't on the server side- the server never has to render anything on the screen! Simple enough, right?
NOTE: those gibberishy method names are the ones the decompiler originally spat out. What happened was some brave souls meticulously went through and figured out what the vast majority of classes, fields, and methods were and gave them names as they saw fit. After the code is decompiled, MCP uses the mappings they came up with to replace all the names. I believe you can change the mappings for yourself if you want to rename things, (or contribute possibly), but for more detail, look it up in the MCP readme.
Anyways, what all this means is that you can develop a mod for BOTH the client and server sides simultaneously! After you design that new creature class on one side, you basically copy it over to the other, then you simultaneously make adjustments to preexisting classes on both sides to incorporate it into the engine. It's normally pretty easy to do, actually! Plus, people would love being able to play your mod on both the client and server side, so I heartily recommend modding for both if applicable!
Getting a Feel for Simultaneous Development
Rainbow Sheep for Client and Server Alternate Title: Notch did not create all sheep equal
You know, the normal spectrum of sheep is pretty boring... white, brown, gray, dark gray... *yawn*. Let's make the whole rainbow of sheep, for both the client and server side!
Open up EntitySheep.java on the client side.
Find "float fleeceColorTable[][]" at the bottom of the file. This is your color palette, friend.
Find "int getRandomFleeceColor(Random random)". This basically rolls a die to determine the sheep's color, which happens to be an index in fleeceColorTable. Possible color indices range from 0-15. The possibilities this method currently dictates are 15, 7, 8, 12, 0, and 6... hmm, evidently Notch has something against brown sheep.
Here's what's happening-- Before EntitySheep's wool is rendered, RenderSheep grabs an entry of "fleeceColorTable[]" (an array of 3 floats: red, green, and blue, ranging from 0.0F to 1.0F) and passes it to OpenGL to change the hue of the next thing rendered. Here's what I did:
You can set up possible colors and probabilities however you want, but I prefer not to discriminate against any one color of sheep. Anyways, make your changes in this file, then copy/paste the inside of "getRandomFleeceColor" to it's duplicate method under EntitySheep.java on the server side (the method's name is gibberish, but you can figure it out!) See? That wasn't hard at all, was it? I'd keep the original code commented out in case you wanna go back later :smile.gif: Recompile your mod and show your new sheep friends some love... (it should work for both client and server!)
Tips and Tricks for Simultaneous Programming in Eclipse
Wasn't that fun? Now I'm gonna teach you some good simultaneous-programming practices before we move on to the next challenge (those who have epilepsy or are generally afraid of violently flashing rainbow sheep should not take the next challenge.)
Firstly, see the Package Explorer (docked to the left by default)? I'm gonna show you how to navigate it quickly. Step 1) click on the Package Explorer. Step 2) start typing in the name of the class you want. Step 3) press enter once it's highlighted. Congratulations! You just opened a file like a real power-user. Keep in mind that it highlights the first class that matches what you typed in, so if you meant to grab EntitySheep from the client side but initially clicked on a class after it, you'll grab the one from the server side instead. This can get annoying, so I generally open any duplicate files at the same time then try to keep them open in tab bar for quick access.
Secondly, see those tabs at the top of the Eclipse text editor? Every file you open in Eclipse get placed up there. Try to keep the tabs of duplicate classes right next to eachother, you'll save yourself some time that way. If you've opened a lot of files, the excess tabs get pushed to the ">>" button to the right.
Psychedelic Sheep Rendering Alternate Title: ...what the hell was in that porkchop?
Alright, ready to begin? We're gonna be working on RenderSheep.java which is only on the client side. However, before we do that, open up EntitySheep (on the client side). Highlight "fleeceColorTable"'s name, then either a)press Ctrl+Alt+H, or b)right click, then select "Open Call Hierarchy." This should bring up the Call Hierarchy panel at the bottom of the screen. This shows every single place in the project where "fleeceColorTable" was referenced. You can either click or simply use the arrow keys to navigate to the one place this field is used, RenderSheep.java! Get good at doing this and you'll be putting out mods faster than the Yogscast could ever cover!
So let's take a look at the second method of RenderSheep.
protected boolean func_176_a(EntitySheep entitysheep, int i, float f)
{
if(i == 0 && !entitysheep.getSheared())
{
loadTexture("/mob/sheep_fur.png");
float f1 = entitysheep.getEntityBrightness(f);
int j = entitysheep.getFleeceColor();
GL11.glColor3f(f1 * EntitySheep.fleeceColorTable[j][0],
f1 * EntitySheep.fleeceColorTable[j][1],
f1 * EntitySheep.fleeceColorTable[j][2]);
return true;
} else
{
return false;
}
}
Ok, lets dissect this. First of all, note that this method is called 4 times in a row for each game tick (there are about 20 ticks in a second), "i" being incremented each time. If you wanna investigate this, highlight the method's name, use the Call Hierarchy tool, and repeat until you see what I'm talking about. This is so a class can render up to 4 different things if it so chooses, but RenderSheep only needs to render one special thing (its wool). Thus, we only need to do something when "i == 0" and the sheep is not sheared (otherwise we return "false" to indicate we did nothing). "loadTexture(String)" is a method on RenderSheep's highest superclass, Render, that takes a string and loads the texture from the .minecraft directory (in this case, the wool texture). "f1" will hold a float ranging from 0.0F to 1.0F representing the entity's current light level. Next, we grab the sheep's color index and stick it in "j". Finally, we make a call to OpenGL... "glColor3f(float,float,float)" takes in 3 floats representing the color channels red, green, and blue (respectively). This method call results in EVERYTHING rendered afterwards being tinted the color you gave it, until either the color is changed by another OpenGL call or "popMatrix" is called (don't worry about that one just yet :smile.gif:). We grab each channel using "fleeceColorTable" and "j", then multiply them by the brightness factor "f1", resulting in a properly-shaded, well-rendered sheep.
If you didn't multiply by the brightness, the sheep's wool would glow brightly no matter where it was... hmm, that sounds interesting... also, if you were to grab a random color every tick, that'd look fairly ridiculous... hmmmmmmm... your task is to do both of these things! If you're having trouble, here's what I did:
protected boolean func_176_a(EntitySheep entitysheep, int i, float f)
{
if(i == 0 && !entitysheep.getSheared())
{
loadTexture("/mob/sheep_fur.png");
float f1 = 1.0F;//entitysheep.getEntityBrightness(f);
int j = EntitySheep.getRandomFleeceColor(entitysheep.rand);//entitysheep.getFleeceColor();
GL11.glColor3f(f1 * EntitySheep.fleeceColorTable[j][0],
f1 * EntitySheep.fleeceColorTable[j][1],
f1 * EntitySheep.fleeceColorTable[j][2]);
return true;
} else
{
return false;
}
}
This will use your customized "getRandomFleece()", but feel free to determine the color some other way. If you were truly amazing, you could design a sheep that gradually phases through each color of the rainbow... YOU HAVE BEEN CHALLENGED! Anyways, recompile, start up your world, and see what happens! It's ok man, those sheep are perfectly harmless, they're just a little... psychedelic. They are real though.
EDIT: I solved my own challenge. These sheep really freak me out.
protected boolean func_176_a(EntitySheep entitysheep, int i, float f)
{
if(i == 0 && !entitysheep.getSheared())
{
loadTexture("/mob/sheep_fur.png");
float f1 = entitysheep.getEntityBrightness(f);
//int j = entitysheep.getFleeceColor();
//GL11.glColor3f(f1 * EntitySheep.fleeceColorTable[j][0], f1 * EntitySheep.fleeceColorTable[j][1], f1 * EntitySheep.fleeceColorTable[j][2]);
float red,green,blue;
int ticks = entitysheep.ticksExisted % 90;
if (ticks < 30)
{
red = (30-ticks) / 30F;
green = ticks / 30F;
blue = 0;
}
else if (ticks < 60)
{
red = 0;
green = (60-ticks) / 30F;
blue = (ticks-30) / 30F;
}
else
{
red = (ticks-60) / 30F;
green = 0;
blue = (90-ticks) / 30F;
}
GL11.glColor3f(f1 * red, f1 * green, f1 * blue);
return true;
} else
{
return false;
}
}
Hopefully you're on the road to using Eclipse like a pro, and I encourage you to explore the project, mess around, and see what you can do in Minecraft! In the process, you might even think of a mod no one has thought of before! Have fun with it, and be ready to mod some more when we meet again...
Added a section on using Eclipse and developing for both the client and server simultaneously. You get to make your first mod... an entire rainbow of sheep!
This is exactly what I need! Thanks. I'm fairly experienced in the C languages, but java's small differences are more confusing than welcome. I read the first...Maybe 1/3 of this tutorial, and I can tell it's gonna be awesome :wink.gif: Good luck working on it! Can't even imagine how long it's been...
I'm flattered! It's taking a while, but it's worth it :tongue.gif: I just remembered starting out and not seeing anything immediately helpful, just a bunch of tutorials geared at people who wanted to make slight changes and didn't know how to program. I figured, now that I'm knowledgeable, I'd share absolutely everything I know, to an extreme, haha. Let me know if anything needs to be clarified-- hopefully all the terminology and ultra-compound sentences are clear enough.
This is some top-notch (no pun intended :tongue.gif: ) work you've done here. I'll be honest, I never understood bits and bit-shifts until now. Thanks for this, I'll be referring to it often :smile.gif:
I have very limited knowledge on what the heap and the stack are (I know they have something to do with memory). Can I get some clarification on what those are exactly?
I have very limited knowledge on what the heap and the stack are (I know they have something to do with memory). Can I get some clarification on what those are exactly?
The heap and stack are somewhat abstract concepts. Hmm... I should probably add another in-depth section for that, lawl.
Imagine you have a stack of paper. You can really only add or remove sheets from the top of it, correct? Trying to remove any other sheet may very well mess up the stack! We really don't want that. Therefore, the stack of paper is what we'd refer to as a "FILO" (First-In Last-Out) data structure. By nature, the first sheet of paper added MUST be the last sheet of paper removed (and so it is with THE stack!). Just so you know, a "FIFO" (First-In First-Out) data structure exists as well, better known as a "queue." This is comparable to a line of people waiting to ride a roller coaster- "the early bird gets the worm," right?
So, we just described "a stack," but what is "the stack???" Well, "the stack" is programmer slang for the data structure that holds most of your program in memory (Everything else is on "the heap!") Think of it as a stack of blueberry pancakes, each pancake being a block of memory (known formally as a "scope"). The blueberries are its variables (variables "allocated on the stack"). Pancakes are essentially managed via the curly braces- the left curly places a pancake, the right curly removes a pancake (and all of it's delicious variables). By the nature of the stack, of course, the most recently placed pancake is the one that is removed. Observe:
{
//Initial pancake
int i = 32;
{
//New pancake
int k = i;
}
//The new pancake is gone :sad.gif:
}
Notice how "i" can be referenced from within the new pancake? This is because nested scopes (pancakes higher on the stack) have access to all the scopes that contain them (pancakes underneath them). Additionally, "k" cannot be referenced from outside the new pancake... this is because any variable allocated on the stack is destroyed when its scope's curly brace is reached (destroying a pancake destroys all its blueberries!) You may already be aware of how all of this works in practice, but hopefully now the terminology has become meaningful (which will allow you to understand the next topic, the heap...)
The actual structure of the heap is quite complicated, which is why it is simply called "the heap." Think of it as the pile of clothes sitting in your room. Its structure is unimportant to you- all you really care about it is that it is a home to your clothes, either currently being worn or too dirty for you to wear. You may toss new clothes into it, but sooner or later, after you've re-worn that shirt enough times, you'll stop wearing it, and you'll forget it's even in the pile- after all, you only really care about clothes you're still wearing! Eventually, however, your mom will come along and recycle those dirty old clothes into ones that are good as new, which you will care about again :smile.gif:
Now, go back to being a programmer. Each article of clothing is a variable, the pile of clothes is "the heap," and your mom is "the garbage collector." When you allocate a new variable on the heap, it takes up memory. After a while, that variable will fall out of use, but unlike the stack, it must rely on an invisible force to free up that memory again- the garbage collector (your mom)! Now, Java's mom is a fantastic mom! She can do TONS of laundry! In a household of four children, she has no trouble keeping the place running smoothly. However, she is STILL only human, and limited by factors that simply cannot be changed- therefore, in a household like Minecraft that already has THIRTY children, we must take extra care to reduce our consumption of clothes so we don't end up waiting around just for a decent pair of underwear! We must rewear our clothes as much as humanly possible!
So how does this translate to code? How do I allocate a variable on the heap, anyways? Well, it's done via the "new" keyword. Think of the heap as a place where variables are free from the rules of the stack- these variables are in no manner bound by any communist notion of "scope!" Variables may roam freely, their creation and destruction being independent of the stack. This is accomplished by the use of "pointers," which themselves actually exist on the stack, but "point" to variables that exist on the heap. Confusing enough? In many languages, you'd have to use special syntax to clarify that you're referring to the variable that is being POINTED to, NOT the pointer itself... however, Java and C# syntax eliminate the need to do this by simply forbidding you to make changes to the pointer itself- change to the pointEE is always assumed. Observe again:
{
//Create a pointer on the stack
MyClass a;
{
//We allocate a variable on the heap, pointed to by "b" on the stack
MyClass b = new MyClass();
//Now we make "a" point to what "b" was pointing at!
a = b;
}
//"b" no longer exists here, but what it was POINTING at does!
//We can get to it via "a!"
a.print();
}
What I've been referring to as "pointers" are ACTUALLY known as "references" in Java. IMHO, the distinction is frivolous and technical, but you should know it. Basically, "pointers" in the traditional sense are just addresses in memory, which you can manipulate directly (like in C, C++, and objC!) In fact, you can treat them just like any other integer (and you can even treat integers like pointers! Always a questionable language design decision :smile.gif:) References, on the other hand, are NOT directly manipulable- you can only do a limited number of things with them (mostly just assignment and generation via the "new" keyword). This is because 1) it prevents you from pointing to just ANY location in memory, which is potentially very, VERY dangerous, and 2) "references" may actually contain more information than just an address, depending on the language, thus making "pointer arithmetic" impossible to begin with.
Again, I did not go into detail about the actual implementation of the heap because it's quite complicated and unnecessary to know for introductory level programming. It is, however, good to know for advanced programming (that's what we're here for, right?), so I'll definitely cover this in the future. For the most part, though, knowledge of the heap's implementation is purely technical and only but so useful. For now, just try to conceptualize the heap as a vast ocean, in which your program is a boat... if you create a variable in the ocean, it will only remain afloat so long as something is something is holding onto it (a pointer!). If all ties between your boat and the variable have been severed (no pointers are pointing at it), however, it will sink to the bottom, only to be reclaimed by the unforgiving sea...
You can think of the aforementioned garbage collector as the mutant space octupus residing in the deepest abysses, transmuting your lost variables into replenishable sand!
Hope that was helpful- when I get internet back at my apartment, I'll edit this and move this to the introductory part of the guide, that way I can archive it on my PC :wink.gif:
@alec_ It'll eventually come up, I'll cover it at some point. Though later I'll include how to fit this in nicely with preexisting code, for now you could probably just import org.lwjgl.input.Keyboard wherever and use methods like Keyboard.isKeyDown(Keyboard.KEY_EQUALS) to get things done. If you want, try exploring the KeyBindings and GameSettings classes- see if you can't figure out how to add your key to the game's list of keys, that way users will both see it in the options screen and be able to change the binding if they want. NOTE: If you want to properly name the key binding on the screen, you'll have to copy the 'lang' folder from <root>/temp/bin/minecraft and paste it into <root>/bin/minecraft, open the en_US file inside the folder using a text editor, then add a line of code like "key.belch=Belch" depending on what you entitled the key in the GameSettings class. Try figuring it out, it should be a fun challenge. Just remember to add your keyBinding to each hashtable in the class. I believe by simply adding your keybinding to the preexisting list of bindings, it will appear in the options screen :smile.gif:
This is perhaps the best tutorial I've read thus far. As someone who has a degree in this, you provided exactly what I was looking for, a guide that explains how/why the things work like they do, rather than just saying "type this, type that, change this, boom you can mod now". Looking forward to seeing this grow.
nice work. its good to see some explanations and stuff. too many tutorials seem to be written by people who barely understand what they are doing (on other forums asking for basic help/telling us to do things wrong etc). ill be following this thread for sure.
You... Are... my idol =P lol. Seriously, though, I need to learn some more so that I can figure out how to do advanced things like you have been doing. Keep up these tutorials, and you'll have 's for life from every serious modder in these forums =D
This is AWESOME! Not that I understood the majority of it. I have a conceptual understanding of basic programming with 0 real experience applying any of it. Now if only I can muster the patience to teach myself java and get some practice, it will make some sense...
New!!!
Hack Slash Mine
This is my mod! Are you convinced I know what I'm talking about!?!
Hack Slash Mine thread!
Hello! And thank you for your interest in modding, you crazy thang. If you're looking for a general explanation or introduction to the Minecraft source code so that you can do some very in-depth modding, you've come to the right place. I'm mostly writing this with the intention of it being a handy modding reference one day, so if you're looking for something specific (and I mean specific), it may very well be here in the future. If you're making something like a full-fledged Pokemon mod, an entirely new in-game GUI, a rogue-like dungeon generator, or even... THE ELUSIVE DRAGON MOD (God help us all), this is the guide for you! For this in-depth modding guide, I'm going to assume the following...
Prerequisites For This Guide
NOTE: This is a guide primarily for those interested in advanced modding. I'm not going to assume that you're using ModLoader or any other modding API because, if you're mod is particularly expansive and/or innovative, there may not be an API like Modloader flexible enough to do what you want. That's why Notch announced there wouldn't be an official Modding API, simply because you could never make an API good enough to do everything you'd want it to. Instead, they're releasing the source code! So, if you can pull it off with Modloader, great, you should do that! Your mod will integrate seamlessly with other ModLoader mods, which you should strive for if possible. Otherwise, don't fret, because I'm not going to assume that you're using it. I may cover ModLoader later, but I'm currently avoiding it myself because my mod is too crazy to work with it (I shall reveal it to the world soon... hehe). The point is, don't expect your mod to work seamlessly with other mods without ModLoader There is a javadoc that comes with ModLoader should you choose to use it, as well as a fine collection of tutorials on the forums. This guide may still prove helpful to you even if you use ModLoader, so read on!
I really want to stress that this is NOT a compilation of tutorials, but rather, a guide and a reference for modding. There will be an occasional example you can follow, but I encourage you to experiment with them, rather than follow them exactly. I will stress details like crazy so that YOU can be a better modder, so if you're looking for something quick and dirty, you might be disappointed. If you want to make a fabulous mod, however, then read on! If you need help with something specific (once this guide has some bulk), try searching the thread for it! There are already some good tutorial compilations out there, actually, but I wanted to take it a step further than that. I don't want to guide you step by step on how to do something specifically, I want you to be well equipped to do whatever you can imagine! I want you to be both self-sufficient and capable of doing whatever your brain can come up with. So, in the process of reading this guide, you should acquire a strong understanding of how the Minecraft source is organized, some good programming practices, how to modify many of the existing Minecraft classes (make new items, block, creatures, recipes, game mechanics, you name it!), how to work a bit with OpenGL, and really start thinking outside the box.
If you want to contribute, make suggestions, etc:
Hmm... this is probably gonna be more like a textbook than a guide XD If you're already a very experienced modder, you may still find some of this information useful, and I may very well find some of YOURS useful if you feel like contributing! Send me a PM if you're up to writing something (or already have something written) and I'll probably edit it and stick it on here with your name branded at the top. If it's something along the lines of a tutorial, please make sure it communicates something generally useful, otherwise I won't add it. The tutorial should be more along the lines of an example of something you're talking about. Describe things broadly, make things generalizable, and do so in the spirit of giving the reader tools that can be widely applied (details on how the Minecraft engine works, etc). Also, PM any suggestions, corrections, or useful additions, I ain't always right. I strive to be perfect! PERFECT!!! I'll definitely try to keep updating this, but feedback certainly keeps me motivated!
Overview
In this first post I'm gonna be talking about some Java specifics and how it ties into Minecraft, along with ways to show the garbage-collector some love since the GC is currently a huge problem for Minecraft. You'll also learn about bitwise operations! Hopefully you'll both get the hang of Java and get to where you can begin experimenting with modding in the process! If you're a Java expert/guru who knows many of the inner-workings of the compiler, you probably won't need to read this one (actually, you could probably just open up the project and start experimenting and come back later once you've had some fun). Otherwise, here's a couple of things you should know about Java...
Some Details About Java
How Java Works
Java exists in a sweet gray spot between compiled and interpreted languages. It is compiled into what is known as "byte code," which you can think of as a version of your code that's been optimized by the compiler and reduced to a much simpler set of instructions (and thus a much fatter/faster set of instructions). The byte code is then interpreted by the Java Virtual Machine (JVM) at run-time, which means Java relies on another executable to carry out it's instructions, instead of being compiled into an executable itself. This byte code is practically platform independent, because it can run any platform that supports the JVM (a lot of platforms). The JVM's what you always have to install on your computer before you can use Java for the first time... good to know, right?
Note that Java is only as platform independent as the JVM is. So while you're code may technically run on any platform with the JVM, that doesn't mean that the JVM for that platform is any good... that's the main reason Minecraft doesn't run well on a Mac! It runs fine on my MacBook Pro, but that's because I paid $3000 for it... *facepalm* So Oracle may claim that Java is platform independent, but I say take nothing at face value
Java is Garbage Collected
Java is a garbage-collected object-oriented language with a C-like syntax. Remember all that memory-management you might have been doing in C++ or Objective-C? You don't gots to do it no more! You never have to explicitly deallocate memory. Iow, no more...
The Java garbage collector automagically manages memory for you, giving you extreme convenience at the price of run-time performance. Normally, this is of little consequence, but in a real-time application like Minecraft, you wind up getting major lag spikes or "hiccups" as you play. This is because the GC periodically checks if you are short on memory, then sweeps through all the memory in your program to free up any memory that isn't currently in use... THIS TAKES FOREVER, but is the price Mojang pays for using Java. It's great for us though, because Java is relatively easy to decompile, meaning we get to gank the source code (legally in this case) and make mods!
Java is a C-Like Language
Did I mention that Java is a C-like language? This means that Java is considered to have a similar syntax as plain ol' C. In both C and Java (along with objC, C++, and C#), this is a valid code fragment:
Order of operations is basically the same among every widely used C-like language. Like C, the use of assignment statements in expressions is valid in Java, but they have a lower precedence than most everything else. So the following two "if" statements are very different:
Java has the incremental operators (++,--) and all the compound assignment operators included in C (+=,-=,*=,/=), along with all the regular mathematical operators, so you should be feeling pretty comfortable with the syntax by now.
How Java Treats Variables
Java uses what is known as a "reference model" for classes. This means that you cannot instantiate a class on the stack (as possible in C++ or with structs in C#. This is called using a "value model"). Classes are always allocated on the heap. Observe!
While in C and C++ you must use the '*' or '->' operators to explicitly dereference pointers, in Java there is no such thing as "dereferencing" a pointer; classes are always allocated on the heap, so dereferencing is assumed! The same is true for classes in C#, whereas structs in C# are assumed to be allocated on the stack. Java has no structs, but primitives (int, float, char, long, etc) in both Java and C# are allocated on the stack.
REMEMBER: value model == allocated on the stack, reference model == allocated on the heap. Classes in Java use a reference model, primitives use a value model.
Classes in Java
In Java, every class must have at least one constructor. If you don't define any, the default constructor is implicitly defined for you (one that does nothing and accepts no parameters). This is identical to the way C++ and C# handle constructors. Because you're not responsible for any memory management in Java (thanks to the garbage collector), there is no destructor in Java.
Something strange and magical happens before the constructor is called in Java... check this out:
Wtf? This may look crazy at first, but this is one of my favorite parts about Java (and C#). Right before the constructor is executed, all the initialization statements declared outside of a method fire, meaning you may not even need to define a constructor! Furthermore, fields and methods may be declared in any order and reference each other freely- there is no need to prototype anything within a class! This allows you to organize methods and fields according to how they relate, giving you more modularity and less conceptual strain while programming! Unfortunately, the decompiled Minecraft code is not organized as Mojang programmed it- all fields have been pushed to the bottom of the class and methods have been pushed to the top. If you're adding functionality to any existing classes in the game, I recommend placing your new methods and fields right next to eachother at the very bottom of the class. This is especially convenient if you're copy-pasting from an old version of Minecraft to a new one (at least if you're doing it manually I believe there are automatic updating tools, but I'm not sure how much work they actually save you. It took me about a day to copy-paste a massive project from 1.4 to 1.5, hehe, but even if you auto-updated you'd have to run through and make sure your code is working properly, so you might as well have it organized)
Interestingly, Java enforces a 1:1 relationship between classes and the .java files that contain them. This means that EVERYTHING must belong to a class or an interface (even the "main" function!)... however, classes may contain other classes. Additionally, classes may only inherit from one other class in the traditional sense ("single-inheritance"), but blurs the line a bit with interfaces...
Interfaces
A class can have as many interfaces as you want. Interfaces are comparable to the following:
Here's what some typical class declarations might look like:
Alright, let's have a look here. "Gamesprite" is a class we are declaring, which is a subclass of "Quadrilateral" ("extends" is the keyword for traditional subclassing) and has the interface "IDrawable" ("implements" is the keyword for declaring Interfaces). Firstly, look at the syntax of "DrawDisThang"s declaration and definition (in the interface and class, respectively)- they are the same except that the declaration terminates with a semi-colon, whereas the definition terminates with the method body (just like a regular method). Easy peasy. Secondly, notice the naming convention for Interfaces- it's generally a good idea to prefix your interfaces with "I", otherwise it might start getting confusing (it's your decision, though). Thirdly, notice that "Polygon" has multiple Interfaces and only one superclass. Remember, you can have as many interfaces as you want, but only one direct superclass (a class's superclass's superclass is still considered to be a superclass of the lowest level class, though, just not directly. You can picture single-inheritance as an upside-down tree with the highest level class at the top, and it's subclasses forming the branches underneath it. Each and every subclass inherits the methods and fields of the superclass above it, meaning EVERY subclass inherits from the highest level superclass. You'll see this quite often in Java, and Minecraft is no certainly no exception).
It's always hard to come up with understandable examples for polymorphism (I've never seen one I liked), but you'll get it when you start working with the code. You never really think of a class as "the class, it's superclass, and ALL of its interfaces" at any point in time, you just think about the class itself and are aware of the additional things, only thinking about them in detail when necessary (reduction of conceptual strain is one of the reasons polymorphism exists!) Besides, Eclipse makes jumping to a method declaration in a superclass as easy as right clicking the method call then selecting "Jump to Definition."
Methods and Fields in Java
Methods are very similar to what you would find in C#. The grammar for a method declaration looks like this: <keyword list> <return type> <methodID> '(' <parameter list> ')' '{' <method body> '}'. The grammar for a method call looks like this: <class instance> '.' <methodID> '(' <parameter list> ')'. Here are some examples:
You should already be familiar with the concepts of "public," "protected," and "private" if you know a C-like OO language (objC doesn't technically have "private" methods because objC is retarded, but you'll be alright). A class's "public" fields/methods are accessible to everyone, whereas "protected" ones are accessible only to the class and its subclasses. "Private" methods/fields are accessible only to that class, NOT its subclasses. A good rule of thumb if you're uncertain is to start out "private" and increase visibility as necessary- this is especially nice for code completion (frequently called "Intellisense" in Eclipse, brought up with Ctrl+Space as your typing) so you won't have to choose among a whole bunch of fields and methods you don't need.
Static methods/fields are those declared on the class itself, as opposed to being on an instance of the class. This is done using the "static" keyword. Instances of a class can access static methods/fields freely, but static methods cannot directly access instance methods/fields; if you wanted that, you'd have to devise something fancy, which I'll show you in a bit!
The "final" keyword is basically the same as "const" in C, C++, and objC. It means that once something has been assigned to it, it can never be assigned to again. The compiler must be able to confirm that it will only happen only once, so declaring a "final" variable then assigning to it in a "for" loop you know will only iterate once ain't good enough!
In general, if you're programming for efficiency, you should try to define things as "static final" fields whenever possible. Why? The compiler basically just replaces every use of the field with the value you assigned to it, both reducing processing time and moving memory consumption from RAM to system memory! In terms of efficiency, doing things statically is the way to go.
Here's a neat example for ya (very similar to what you'll be seeing in several Minecraft classes, actually):
Hopefully that helped you understand how you can tie building blocks as simple as visibility, "static," and "final" together to do some very interesting things. You'll see a format very similar to this in the Item and Block classes. Additionally, several classes (ie CraftingManager) define a single public instance statically using a private constructor, ensuring that only one instance exists throughout the life of the program. Cool beans.
Speeding up your Mod and Helping the Garbage Collector
(This is only really necessary if your mod takes up a lot of processing power (ie a radar, a new creature with a ton of things happening with every game tick, a complex new gui, etc) or is otherwise core engine related)
Here's a few general things you can do to ensure your mod is running efficiently:
Unfortunately with Java, since you cannot EXPLICITLY instantiate a class on the stack (Java uses a "reference model" for classes), every method/field on a class has an extra level of indirection; you must go through a pointer to get to them, which ultimately makes Java a bit slower from the get-go (in addition to the fact that anything allocated on the heap must be garbage collected *facepalm*). HOWEVER, the compiler can sometimes deduce that a class instance will not be used anywhere else in the program, and can therefore (unbeknownst to you) allocate it on the stack to both reduce garbage collection and remove that extra level of indirection. This is only the case if the compiler can guarantee you created the class instance in a method and never passed it out to anything else (you never returned it, passed it to another method call, assigned it to another variable's field, assigned it to a static field, etc). If you're doing anything processor intensive in your mod and you need a little extra grease (ie your mod draws a live radar with OpenGL calls, your mod regularly updates some hossly cellular-automata, etc), then bear this in mind so that you don't make the garbage-collector any slower in Minecraft than it has to be! The GC is already doing the best it can, give the poor thing a rest! Don't make Minecraft "hiccup" any more than it already does or no one will want to play your mod (and remember that those hiccups are probably gonna get worse as Mojang develops the game, so "running good enough" today may be "barely running at all" tomorrow.)
Bitwise Operations (If you're doing anything with Chunks, OpenGL, color, or the general core engine of Minecraft, read this!!!)
The Basics
Of particular importance are the bitwise operators! Minecraft makes gratuitous use of them. They are &, |, ^, ~, <<, >>, and >>>. The following statements all assign '5' into 'var':
Those are the most basic bit operations you'll be seeing around the place. Note that '&'ing a variable is often referred to as "masking" it, since it is frequently used to hide bits you don't care about, which you'd probably be doing if you were working with OpenGL. EXOR is different from OR in that EXOR only returns "true" when the two bits are different. That is, 1^0 == 0^1 == 1, whereas 0^0 == 1^1 == 0. Interestingly, 0x5 ^ 0xF == ~0x5, whereas 0x5 ^ 0x0 == 0x5, so the former is a complement and the latter is redundant. NOTE: Engineers would refer to "flipping the bits" as a "one's complement." A "two's complement" is when you flip the bits then add 1, which is significant because it may affect the format of the numbers you're working with. Anyways, NOW YOU KNOW!
Bitshifts
This part may be useful if you're working with OpenGL or Chunks... the following statements all assign "6" into "var":
If you're working with OpenGL at all, the bit-shifts are useful for grabbing color channels out of a color represented by an int. So let's say you've got purple represented in RBGA (0xFF00FFFF) and you wanna grab the B channel. Just say "byte var = (purple >>> 8) & 0xFF" and you've got that channel! For colors, use ">>>", NOT ">>", or it'll wind up screwing you over some day.
WOW that was technical. Let's take a break. Go grab some coffee and meet me again later, then we shall dance the dance of the modder... But before then, you should be sure to at least look around the Eclipse project, particularly the Items class, make some fun little changes, recompile, and see what happens! I personally prefer the stackable Wooden Sword of Over 9000 damage, but that's just me.
You get to make your first test mod! Are you excited? You should be. I'm going to teach you some good ways to navigate the Minecraft projects using Eclipse.
Similarities Between Client and Server
Alright, go ahead and pull up the workspace in Eclipse. Before we begin looking at the code, notice that you have two projects- "minecraft" and "minecraft_server." The first is the client side, the second is the server side. Open them both up. Notice how many of the same classes appear in both projects? If you were to open one up, you'd notice that, apart from the gibberishy, decompiled method/field names, these projects are 95% identical! This is because Mojang basically had one body of files that was cross-referenced between two seperately compiled projects. If a method or class wasn't referenced by a project, it wasn't compiled into it! That's why the decompiled client side you're looking at has a bunch of "Renderer" classes that aren't on the server side- the server never has to render anything on the screen! Simple enough, right?
NOTE: those gibberishy method names are the ones the decompiler originally spat out. What happened was some brave souls meticulously went through and figured out what the vast majority of classes, fields, and methods were and gave them names as they saw fit. After the code is decompiled, MCP uses the mappings they came up with to replace all the names. I believe you can change the mappings for yourself if you want to rename things, (or contribute possibly), but for more detail, look it up in the MCP readme.
Anyways, what all this means is that you can develop a mod for BOTH the client and server sides simultaneously! After you design that new creature class on one side, you basically copy it over to the other, then you simultaneously make adjustments to preexisting classes on both sides to incorporate it into the engine. It's normally pretty easy to do, actually! Plus, people would love being able to play your mod on both the client and server side, so I heartily recommend modding for both if applicable!
Getting a Feel for Simultaneous Development
Rainbow Sheep for Client and Server
Alternate Title: Notch did not create all sheep equal
You know, the normal spectrum of sheep is pretty boring... white, brown, gray, dark gray... *yawn*. Let's make the whole rainbow of sheep, for both the client and server side!
Here's what's happening-- Before EntitySheep's wool is rendered, RenderSheep grabs an entry of "fleeceColorTable[]" (an array of 3 floats: red, green, and blue, ranging from 0.0F to 1.0F) and passes it to OpenGL to change the hue of the next thing rendered. Here's what I did:
You can set up possible colors and probabilities however you want, but I prefer not to discriminate against any one color of sheep. Anyways, make your changes in this file, then copy/paste the inside of "getRandomFleeceColor" to it's duplicate method under EntitySheep.java on the server side (the method's name is gibberish, but you can figure it out!) See? That wasn't hard at all, was it? I'd keep the original code commented out in case you wanna go back later :smile.gif: Recompile your mod and show your new sheep friends some love... (it should work for both client and server!)
Tips and Tricks for Simultaneous Programming in Eclipse
Wasn't that fun? Now I'm gonna teach you some good simultaneous-programming practices before we move on to the next challenge (those who have epilepsy or are generally afraid of violently flashing rainbow sheep should not take the next challenge.)
Firstly, see the Package Explorer (docked to the left by default)? I'm gonna show you how to navigate it quickly. Step 1) click on the Package Explorer. Step 2) start typing in the name of the class you want. Step 3) press enter once it's highlighted. Congratulations! You just opened a file like a real power-user. Keep in mind that it highlights the first class that matches what you typed in, so if you meant to grab EntitySheep from the client side but initially clicked on a class after it, you'll grab the one from the server side instead. This can get annoying, so I generally open any duplicate files at the same time then try to keep them open in tab bar for quick access.
Secondly, see those tabs at the top of the Eclipse text editor? Every file you open in Eclipse get placed up there. Try to keep the tabs of duplicate classes right next to eachother, you'll save yourself some time that way. If you've opened a lot of files, the excess tabs get pushed to the ">>" button to the right.
Psychedelic Sheep Rendering
Alternate Title: ...what the hell was in that porkchop?
Alright, ready to begin? We're gonna be working on RenderSheep.java which is only on the client side. However, before we do that, open up EntitySheep (on the client side). Highlight "fleeceColorTable"'s name, then either a)press Ctrl+Alt+H, or b)right click, then select "Open Call Hierarchy." This should bring up the Call Hierarchy panel at the bottom of the screen. This shows every single place in the project where "fleeceColorTable" was referenced. You can either click or simply use the arrow keys to navigate to the one place this field is used, RenderSheep.java! Get good at doing this and you'll be putting out mods faster than the Yogscast could ever cover!
So let's take a look at the second method of RenderSheep.
Ok, lets dissect this. First of all, note that this method is called 4 times in a row for each game tick (there are about 20 ticks in a second), "i" being incremented each time. If you wanna investigate this, highlight the method's name, use the Call Hierarchy tool, and repeat until you see what I'm talking about. This is so a class can render up to 4 different things if it so chooses, but RenderSheep only needs to render one special thing (its wool). Thus, we only need to do something when "i == 0" and the sheep is not sheared (otherwise we return "false" to indicate we did nothing). "loadTexture(String)" is a method on RenderSheep's highest superclass, Render, that takes a string and loads the texture from the .minecraft directory (in this case, the wool texture). "f1" will hold a float ranging from 0.0F to 1.0F representing the entity's current light level. Next, we grab the sheep's color index and stick it in "j". Finally, we make a call to OpenGL... "glColor3f(float,float,float)" takes in 3 floats representing the color channels red, green, and blue (respectively). This method call results in EVERYTHING rendered afterwards being tinted the color you gave it, until either the color is changed by another OpenGL call or "popMatrix" is called (don't worry about that one just yet :smile.gif:). We grab each channel using "fleeceColorTable" and "j", then multiply them by the brightness factor "f1", resulting in a properly-shaded, well-rendered sheep.
If you didn't multiply by the brightness, the sheep's wool would glow brightly no matter where it was... hmm, that sounds interesting... also, if you were to grab a random color every tick, that'd look fairly ridiculous... hmmmmmmm... your task is to do both of these things! If you're having trouble, here's what I did:
This will use your customized "getRandomFleece()", but feel free to determine the color some other way. If you were truly amazing, you could design a sheep that gradually phases through each color of the rainbow... YOU HAVE BEEN CHALLENGED! Anyways, recompile, start up your world, and see what happens! It's ok man, those sheep are perfectly harmless, they're just a little... psychedelic. They are real though.
EDIT: I solved my own challenge. These sheep really freak me out.
Hopefully you're on the road to using Eclipse like a pro, and I encourage you to explore the project, mess around, and see what you can do in Minecraft! In the process, you might even think of a mod no one has thought of before! Have fun with it, and be ready to mod some more when we meet again...
Also, *Reserved for da guide*
This is exactly what I need! Thanks. I'm fairly experienced in the C languages, but java's small differences are more confusing than welcome. I read the first...Maybe 1/3 of this tutorial, and I can tell it's gonna be awesome :wink.gif: Good luck working on it! Can't even imagine how long it's been...
Anthrocraft http://www.minecraft...f=1021&t=231356
Green Screenhttp://www.minecraft...f=1021&t=236906
Minecraft Mojang Fix http://www.minecraft...f=1032&t=26687
The heap and stack are somewhat abstract concepts. Hmm... I should probably add another in-depth section for that, lawl.
Imagine you have a stack of paper. You can really only add or remove sheets from the top of it, correct? Trying to remove any other sheet may very well mess up the stack! We really don't want that. Therefore, the stack of paper is what we'd refer to as a "FILO" (First-In Last-Out) data structure. By nature, the first sheet of paper added MUST be the last sheet of paper removed (and so it is with THE stack!). Just so you know, a "FIFO" (First-In First-Out) data structure exists as well, better known as a "queue." This is comparable to a line of people waiting to ride a roller coaster- "the early bird gets the worm," right?
So, we just described "a stack," but what is "the stack???" Well, "the stack" is programmer slang for the data structure that holds most of your program in memory (Everything else is on "the heap!") Think of it as a stack of blueberry pancakes, each pancake being a block of memory (known formally as a "scope"). The blueberries are its variables (variables "allocated on the stack"). Pancakes are essentially managed via the curly braces- the left curly places a pancake, the right curly removes a pancake (and all of it's delicious variables). By the nature of the stack, of course, the most recently placed pancake is the one that is removed. Observe:
Notice how "i" can be referenced from within the new pancake? This is because nested scopes (pancakes higher on the stack) have access to all the scopes that contain them (pancakes underneath them). Additionally, "k" cannot be referenced from outside the new pancake... this is because any variable allocated on the stack is destroyed when its scope's curly brace is reached (destroying a pancake destroys all its blueberries!) You may already be aware of how all of this works in practice, but hopefully now the terminology has become meaningful (which will allow you to understand the next topic, the heap...)
The actual structure of the heap is quite complicated, which is why it is simply called "the heap." Think of it as the pile of clothes sitting in your room. Its structure is unimportant to you- all you really care about it is that it is a home to your clothes, either currently being worn or too dirty for you to wear. You may toss new clothes into it, but sooner or later, after you've re-worn that shirt enough times, you'll stop wearing it, and you'll forget it's even in the pile- after all, you only really care about clothes you're still wearing! Eventually, however, your mom will come along and recycle those dirty old clothes into ones that are good as new, which you will care about again :smile.gif:
Now, go back to being a programmer. Each article of clothing is a variable, the pile of clothes is "the heap," and your mom is "the garbage collector." When you allocate a new variable on the heap, it takes up memory. After a while, that variable will fall out of use, but unlike the stack, it must rely on an invisible force to free up that memory again- the garbage collector (your mom)! Now, Java's mom is a fantastic mom! She can do TONS of laundry! In a household of four children, she has no trouble keeping the place running smoothly. However, she is STILL only human, and limited by factors that simply cannot be changed- therefore, in a household like Minecraft that already has THIRTY children, we must take extra care to reduce our consumption of clothes so we don't end up waiting around just for a decent pair of underwear! We must rewear our clothes as much as humanly possible!
So how does this translate to code? How do I allocate a variable on the heap, anyways? Well, it's done via the "new" keyword. Think of the heap as a place where variables are free from the rules of the stack- these variables are in no manner bound by any communist notion of "scope!" Variables may roam freely, their creation and destruction being independent of the stack. This is accomplished by the use of "pointers," which themselves actually exist on the stack, but "point" to variables that exist on the heap. Confusing enough? In many languages, you'd have to use special syntax to clarify that you're referring to the variable that is being POINTED to, NOT the pointer itself... however, Java and C# syntax eliminate the need to do this by simply forbidding you to make changes to the pointer itself- change to the pointEE is always assumed. Observe again:
What I've been referring to as "pointers" are ACTUALLY known as "references" in Java. IMHO, the distinction is frivolous and technical, but you should know it. Basically, "pointers" in the traditional sense are just addresses in memory, which you can manipulate directly (like in C, C++, and objC!) In fact, you can treat them just like any other integer (and you can even treat integers like pointers! Always a questionable language design decision :smile.gif:) References, on the other hand, are NOT directly manipulable- you can only do a limited number of things with them (mostly just assignment and generation via the "new" keyword). This is because 1) it prevents you from pointing to just ANY location in memory, which is potentially very, VERY dangerous, and 2) "references" may actually contain more information than just an address, depending on the language, thus making "pointer arithmetic" impossible to begin with.
Again, I did not go into detail about the actual implementation of the heap because it's quite complicated and unnecessary to know for introductory level programming. It is, however, good to know for advanced programming (that's what we're here for, right?), so I'll definitely cover this in the future. For the most part, though, knowledge of the heap's implementation is purely technical and only but so useful. For now, just try to conceptualize the heap as a vast ocean, in which your program is a boat... if you create a variable in the ocean, it will only remain afloat so long as something is something is holding onto it (a pointer!). If all ties between your boat and the variable have been severed (no pointers are pointing at it), however, it will sink to the bottom, only to be reclaimed by the unforgiving sea...
You can think of the aforementioned garbage collector as the mutant space octupus residing in the deepest abysses, transmuting your lost variables into replenishable sand!
Hope that was helpful- when I get internet back at my apartment, I'll edit this and move this to the introductory part of the guide, that way I can archive it on my PC :wink.gif:
@alec_ It'll eventually come up, I'll cover it at some point. Though later I'll include how to fit this in nicely with preexisting code, for now you could probably just import org.lwjgl.input.Keyboard wherever and use methods like Keyboard.isKeyDown(Keyboard.KEY_EQUALS) to get things done. If you want, try exploring the KeyBindings and GameSettings classes- see if you can't figure out how to add your key to the game's list of keys, that way users will both see it in the options screen and be able to change the binding if they want. NOTE: If you want to properly name the key binding on the screen, you'll have to copy the 'lang' folder from <root>/temp/bin/minecraft and paste it into <root>/bin/minecraft, open the en_US file inside the folder using a text editor, then add a line of code like "key.belch=Belch" depending on what you entitled the key in the GameSettings class. Try figuring it out, it should be a fun challenge. Just remember to add your keyBinding to each hashtable in the class. I believe by simply adding your keybinding to the preexisting list of bindings, it will appear in the options screen :smile.gif:
Hey all! Sorry I haven't updated lately, I've been too busy working on THIS!!!
Hack Slash Mine
Hope you like it! Be sure to thumbs up if you do :wink.gif: Updates will resume eventually, but for now, know that I'm putting my time to good use!