Terraria-Specific C# Crash Course By Kalciphoz This is a tutorial that will delve into the basics of C# programming, simplified to the bare basics needed for Terraria modding. The tutorial part is approximately twelve pages long and it will likely take some degree of active effort to achieve its full benefit. Some aspects of this tutorial are specific to tModLoader, but in the event of a new API replacing this, these aspects will likely be updated accordingly. Means of providing feedback on the guide are currently under evaluation. Aim of this Tutorial If you are a casual modder looking to play around with tModLoader and make some low-effort additions, then you will likely find this guide ill-suited to your needs. If you are a spriter, then this guide is not directed towards you, although a graphics designer may benefit from some programming knowledge when cooperating with programmers. This guide is mainly directed towards modders seeking to enhance their coding ability to the point of being able to write their own code independently. If you have previously been searching for code-snippets and copying it mostly character by character, but wish to improve to the point of being able to add new game mechanics, code boss behaviours or similar, then this guide is especially for you. This guide does not currently aim to also teach the mathematics that might be relevant to Terraria mods, though a section dedicated to directing readers towards relevant resources is part of future plans for this guide. For now, I advise anybody looking to code projectile or boss behaviours to familiarize themselves with trigonometry and I advise everyone to learn about functions. Background and Disclaimer I made this guide upon request from another modder, looking to improve his coding abilities in a general scope. While I am able to write code independently of help from others and have attained the skills that many readers are here to learn of, I have no formal training in programming, nor have I undergone education in programming; I am mostly self-taught and have learned most of what I know with the purpose of creating mods for Terraria. Though this guide might improve your general programming ability, it will not be sufficient in scope to learn programming as a general skill, but on the contrary, the aim is to be accessible to people who have recently started Terraria modding and have no familiarity with general principles of programming. TUTORIAL FORMAT This tutorial will go through some of the most basic concepts in C# programming. The format consists of separate sections, each dedicated to a subject. They will contain links to a syntax-highlighted pastebin, which you will examine with the help of this guide. Going through the explanations, you will frequently come across words marked with an asterisk (*), signifying that the term is part of programming terminology, and that you will find it in the pastebin link, written in all caps. At the end of each section, you will find a list of some of the terminology used so far. You will want to be familiar with all the listed terminology before moving on, but do not worry, there is not much. When reading the explanations, I strongly suggest you keep the relevant code examples ready in another tab for quick referencing. Additionally, you will come across links to pages that are not pastebin. Those links are all optional and if you do not understand their content, just proceed with the guide. When looking at the pastebin links, look at the text box marked by “C#” wherein some of the words are coloured, rather than the “RAW Paste Data” VARIABLES AND PRIMITIVE TYPES http://pastebin.com/XPSq1Abm/ Variables are named values that can be changed. Variable definitions* consist of, at a minimum, a type* (int, in the example provided) and a name. I will further explain types in later sections, but for now, we will focus on int, which is a numeric integer value, going from -2,147,483,648 to 2,147,483,647, known as the minvalue and maxvalue respectively. Variables of this type can be set to a specific value by writing an equals sign (see variable initialization in the code example) Null Some types are nullable, meaning their values can be null (think n/a, essentially). In the code example, the example_integer is null right after its definition. If you tried to decrease or increase its value at this step, the program would give you a fatal error known as the NullReference Exception. Fortunately, we can do something about this by initializing* the variable. For the sake of convenience, this can be done in the same step as the variable definition, as on the last line of the code example. Two types of ‘types’ Variable types* can either be primitive types, or they can be classes. The int example is a primitive type. They can be distinguished from classes by the fact that classes are normally capitalized and highlighted in cyan, whereas primitive types are highlighted in blue. Classes as types will be discussed in the next section, but we will focus on primitive types for now. Primitive types are written in lowercase and highlighted as blue when using Visual Studio. Here’s a full list, but for general modding, you will only need these: string, int, long, double, float and bool. strings are for text variables, and their values need to be surrounded by quotation marks, like so: string s = “Hi, I am a string.”; strings can contain all sorts of characters, including spaces and special characters, as well as some stranger things we will not go into. We have already discussed ints to sufficient detail, but in the rare event that you need larger numbers than can be contained in a normal int, use a long. Next up is double, which is a decimal number, unlike an int, which is always a whole number. Next up is a float, which for our purposes is the same as a double, but you have to write an ‘f’ after the number, like so: float example_float = 4.2f; We will discuss bools in a separate section. Casting/converting types Say we wanted to increase the damage of an item based on its knockback. The intuitive thing to do would be to write the following: item.damage += item.knockBack; However, this will not compile, as item.damage is an int value, and item.knockback is a float value. To fix this, we will do something known as type casting (also sometimes referred to as parsing, which is a slightly broader term), which is done like so: Item.damage += (int)(item.knockBack); Doing this will convert the float value to an int value, allowing us to add it to the damage. This will also round down the value to a whole number. For other rounding mechanisms, see https://msdn.microsoft.com/en-us/library/system.math(v=vs.110).aspx/ or ask a more experienced modder for help. List of terms: Variables Defining a variable Types Null and NullReference Exception Initializing a variable Primitive Types: string, int, double and float Type Casting CLASS STRUCTURE Let’s examine a very simple class: http://pastebin.com/LbwaVN4B/ A class consists of, at a minimum, a namespace* and a class definition*. They can also have an optional constructor*, which will be explored later in this section and the ones following. Namespace* Namespaces are similar to file addresses in windows. Namespaces follow the name of a folder, but unlike in windows, the folders are separated by dots rather than slashes, for example: System.Exception Class definition* This is the name of the class. It is often preceded by an access keyword, such as public or private, but for the purposes of general modding, you will use the public keyword. Class Instantiation As was mentioned in the variables and primitive types section, classes are a form of types. Their behaviour is somewhat different from primitive types though, as will be explored shortly. Sometimes, a primitive type simply is not sufficient for our purposes when creating variables. Let’s use the Item class as an example: public Item i; Like in the first code example, this is a variable definition. Unlike in the first code example, this variable uses a class as a type. Whenever an item is dropped, crafted, gathered or generated, a variable of the type Item is created. This is called instantiating, or making an instance of the class. The player inventory is a long array (more on that later) of Item-variables. Variables that are instances of a class are called objects, and you should by now have an idea why this is extremely useful. This brings us to the next section, but first: List of terms: Class Class definition Instantiation Keyword: public OBJECTS AND METHODS Objects are at the core of C#. So much, in fact, that C# is called an object-oriented programming language. The biggest difference between objects and primitive variables is that objects can contain their own variables, including other objects. Following along with the public Item i; example, we could do this: int dmg = i.damage; Here, we reference the variable damage, which is local to objects of the type Item. This will give us another NullReference Exception, though, because like variables, an empty definition like public Item i; will point to null. Constructors So how do we initialize an object, you might wonder. We do this by using the constructor mentioned in the class structure section. Starting from the example class from there, which I have linked for your convenience, we could do something like this public ClassTutorial example_object = new ClassTutorial(); So what is a constructor exactly? To answer that, we will have to first explore the topic of methods: In a C# program, all the code happens within methods. In fact, there’s a single parent Method from which all the code starts, known as the Main() method. This is unimportant for Terraria modding, but if you want to do a standalone program, refer to https://msdn.microsoft.com/en-us/library/ms228506(v=vs.90).aspx/ Methods play two main roles in code: They are defined and called. Methods are essentially a procedure that is defined and can be repeated at will without typing the whole thing again. Example method definition: http://pastebin.com/R9VAnWvL/ You can see the method definition as a sort of recipe describing a procedure that happens every time the method is called. Method definitions happen at compilation, so you can place a method at the very end of a class, even if it is called earlier. A method has a list of keywords, (in the example, public and static), a return type*, a method name (ExampleMethod), a list of arguments, and a method body*. The content of the brackets on line 1 is method input, known as arguments. These arguments are labelled like variables and can be referenced in the method body. They cannot be changed, however, unless preceded by the keyword ref in both the method definition and call. You will also notice a new keyword, static. Variables and methods can be either static or nonstatic. If they are nonstatic, you need to reference or call it from an object, like so: i.damage; You can think of these as local variables, because each object has their own copy of that variable and can have different values assigned to it. In some cases, this is not desired. For those situations, we use the static keyword, which will be covered later. “Local variable” means something else in C# though. A local variable is one which is defined inside a method, which means you cannot reference or change it outside of the same method. By contrast, variables declared directly in the class structure are called fields. Example method call: http://pastebin.com/XXC7wKsT/ Here the method is called, meaning that all the code in the method body is run using the arguments (input) enclosed in the brackets. This saves you the trouble of rewriting the entire process. Now we will examine the concept known as return types. In the example method definition, the return type is string. Return types allow us to reference the method like a variable, and assign variables to the return. Now let us return to the constructor example. public ClassTutorial example_object = new ClassTutorial(); Despite being methods, constructors are not actually named. “ClassTutorial” is in fact the return type rather than a name. This is why we can use a constructor to initialize an object, because the constructor actually creates a new object and returns it when called. Since the constructor has no name, it uses a distinct keyword: new This example constructor takes no arguments and does not actually do anything, but if we’d like, we could add some code to the method body. Constructors are commonly used to initialize variables, so we will add a variable. http://pastebin.com/XRcCdhG5/ You will notice the object referenced as this, referring to the object being created. You do not actually need to put this, as it is implicitly understood, except when there’s an argument of the same name as the local variable, like in the example. Now that we have a local variable that gets initialized, we can reference it using any object of the type ClassTutorial, like so: int index = new ClassTutorial(14).index; However, having not stored the object in a variable, all we’ve done is invented a more complicated way to initialize an int, so next we’ll invent a way to retrieve the ClassTutorial object from its index, using something known as arrays. List of terms: Object Keywords: this, new Method Constructor Method call Method arguments Local variables fields ARRAYS AND STATIC FIELDS http://pastebin.com/4aePfqFm/ Arrays were mentioned in the context of the player’s inventory earlier. An array is a long list of variables with a single name and an index. In the example code, you can find an array definition and how to reference the value of an array. Arrays are not limited to primitive types, however. The player’s inventory, for example, is an array of Items, defined something along the lines of: public Item[] inventory = new Item[50]; This allows us to reference an item in the player’s inventory by using Item item = Main.player[Main.myPlayer].inventory[0]; You might have noticed another array being referenced here: Main.player[], whose index we get by referencing an int variable, myPlayer, in the Main class. Let us do something similar in our example class. http://pastebin.com/FH2R9bup/ The constructor now adds the object being created to an array, allowing us to retrieve the ClassTutorial object by writing ClassTutorial object = ClassTutorial.objects[index]; You will notice that ClassTutorial.objects[] is a static array. This means it will be stored directly in the class rather than in the object, and that no object reference is needed to reference the array. Objects, methods, primitive variables can all be static, as can classes, but that is beyond the aim of this guide. Now let us make use of a static variable. Returning to the array example, we might run into a problem if we use the same index twice, because only the second object will take the place of the first. To prevent that problem from occurring, we might do something like this: http://pastebin.com/gs4Y1GVJ/ We have now removed the index as an argument and instead retrieved the index by a value that increments itself every time. There are still some issues with IndexOutOfBound Exceptions, which will occur the 101st you call the constructor, but by now you should have already gotten a basic understanding of arrays, as well as the static keyword. List of terms Array Index Keyword: static IndexOutOfBound Exceptions TMODLOADER AND CLASS EXTENSIONS At the time of writing, tModLoader is the most prevalent modding API for Terraria, and if you want to understand Terraria modding, you will need to know how tModLoader works. To achieve this, you will need to know about a concept called class extension. Class Extension Say you wanted to make a class that had the same basic functionality as ClassTutorial, but with something added on top. The best way of doing this would be to extend the class, looking something like this: http://pastebin.com/s50A24Hc/ You will notice the colon in the class declaration. This makes the class an extension of whatever is written after the colon. However, there’s not much point to this class extension yet, as it doesn’t actually do anything differently from its parent class, so let us change that up a bit: http://pastebin.com/5rcUxJxG/ This is what an extended constructor looks like. The base() is actually calling the original constructor, and any arguments need to go in the brackets. This means that both the original constructor and its extension are executed. override methods This is how tModLoader ties into all of this. Your Mod class is actually an extension of Terraria.ModLoader.Mod http://pastebin.com/U0v2ZJQt/ In this example, we override the method known as AddRecipes() in order to make Meowmere craftable out of thin air. To override a method, we need to put override as a keyword. When you have typed the keyword, Visual Studio will make a popup with available methods to override. Unlike extending a constructor, overriding a method stops the original from being called. If you want to call it, you will have to manually do it, like so: base.AddRecipes(); However, in the case of AddRecipes(), this is redundant, because the base method does not actually do anything at all. The hooks in tModLoader generally don’t do anything except sometimes returning a boolean value, which will be covered in the following section, but first I will link the tModLoader documentation: https://github.com/bluemagic123/tModLoader/wiki/Mod/ And when it comes to documentation, MSDN is extremely useful: https://msdn.microsoft.com/en-us/library/618ayhy6.aspx/ For a more professional and in-depth guide on class extension: https://msdn.microsoft.com/en-us/library/k6sa6h87.aspx/ List of terms Class extension Keywords: base, override Overriding methods MISCELLANEOUS HELPFUL KNOWLEDGE Namespaces pt. 2 / Importing libraries During the tModLoader and class extensions section, you might have wondered about encountering “Terraria.ModLoader.Mod”, when you are likely used to just writing “Mod”, because that is indeed much simpler, but it requires you to write the following above your namespace: using Terraria.ModLoader; Terraria.ModLoader is the namespace of tModLoader, and all its classes are located within that namespace. Statements The term “statement” refers to many things, including declaring a variable, assigning it a value, calling a method, etc., but not if this is done as an argument surrounded by round brackets. All statements should be followed by a semicolon, and it is general practise to put separate statements on separate lines. Booleans bools were mentioned in the start of the guide. They can have the values true and false. Conditional statements like if() and while() take a boolean input. You may have seen structures like if (i > 0) { … } That does not look like a boolean input…? Well, actually it is. “>” is called a comparative operator and it returns a boolean value, true if i > 0, false otherwise. This means that the following is actually valid code: bool b = i > 0; if (b) { /*do something here*/ } Other operators you should be familiar with are && and || These are called boolean operators because they take boolean input and return a boolean value. The first is a boolean AND, which returns true if both inputs are true. The latter is a boolean OR, which returns false if both inputs are false. A boolean value can be negated by writing ! in front of it like so: !true, which rather unsurprisingly evaluates to false. For a full list of operators, see https://msdn.microsoft.com/en-us/library/6a71f45d.aspx/ Loops Loops play a similar function to methods, in that they allow you to repeat similar code without having to type it all over again. When the program encounters a loop, it will be immediately run on repeat until some condition is no longer fulfilled, that is, until a conditional statement evaluates to false. http://pastebin.com/WaVkw3YN/ For loops have a structure as seen in the pastebin. First, the statement known as the initializer is executed, mostly used to declare and assign a variable. Then the condition is checked, and if the condition is true, the statement body is executed, and afterwards, the iterator. If the condition is false, the loop is terminated. Another way to terminate a loop is by the statement: break; For a possibly outdated list of loops in C#, refer to https://msdn.microsoft.com/en-us/library/f0e10e56(v=vs.90).aspx/ List of terms: Statements Primitive type: bool Comparative operators Boolean operators && and || For loops TERMS YOU SHOULD BE FAMILIAR WITH Variables and Primitive Types: Variable Variable definition Type Null and NullReference Exception Variable initialization Primitive Types: string, int, double and float Class Structure: Class Class definition Instantiation Objects and Methods: Object Keywords: this, new Method Constructor Method call Method arguments Local variables Fields Arrays and static fields: Array Index Keyword: static IndexOutOfBound Exceptions tModLoader and class extensions: Class extension Keywords: base, override Overriding methods Miscellaneous Helpful Knowledge: Statements Primitive type: bool Comparative operators Boolean operators && and || For loops Afterword If you have made it this far in the guide and are familiar with all the above listed terminology, then you are off to a very good start when it comes to Terraria modding, and you will likely soon find others asking you for advice. In this event, I encourage you to assist them as it will help develop your own skills, and I would appreciate if you direct them towards this guide. You may find at first that you will keep needing the assistance of others to solve problems in your code, but with a bit of routine, this will change. When you are helped by experienced modders, it is crucial that you make an effort to understand the purpose of their advice and the reasoning behind it, as this will help you anticipate and avert problems when writing code. This concludes the guide, thanks for your interest. TO ADD: Clean code, including: Proper usage of methods for clean code. Constants Section on mathematics Section on visual studio References for common errors in compilation, including syntax errors, null pointers, etc., as well as a guide on how to debug