diff --git a/docs/angelscript/game/meta.json b/docs/angelscript/game/meta.json index 45754fe1..ad750754 100644 --- a/docs/angelscript/game/meta.json +++ b/docs/angelscript/game/meta.json @@ -1,5 +1,5 @@ { "title": "Game", "type": "angelscript", - "weight": 0 + "weight": 1 } diff --git a/docs/angelscript/guide/chapter1.md b/docs/angelscript/guide/chapter1.md new file mode 100644 index 00000000..0831bdc1 --- /dev/null +++ b/docs/angelscript/guide/chapter1.md @@ -0,0 +1,111 @@ +--- +title: Chapter 1 - Introduction +weight: 0 +--- + +# Chapter 1 - Introduction + +## What You Will Learn +In this chapter you will learn about: +- [AngelScript as a programming language](#angelscript) +- [Purpose of AngelScript in Strata Source](#what-can-you-do-with-angelscript) +- [Client-Server model of the engine](#client---server-model) +- [How to load code in the game](#loading-code) +- [Writing your own Hello World program](#your-first-script) +- [Testing out your own code](#how-to-test-out-your-code-in-a-basic-way) +- [Additional tips that might help you](#additional-tips) + +> [!TIP] +> In each chapter, you can easily navigate the page by clicking the links in the "What You Will Learn" section. + +> [!CAUTION] +> This guide assumes you have basic programming skills in languages such as Python, C, C++, Squirrel (VScript), etc. +> It is recommended you already have *some* experience in programming, although this guide aims to be as beginner-friendly as possible. +> Basic concepts will **not** be taught. + +> [!NOTE] +> It is recommended to try out what you learn in this guide as you go through it. This guide will include example tasks for you to attempt as practice. + +--- + +## AngelScript +[AngelScript's home page](https://www.angelcode.com/angelscript/) describes AngelScript as: +> The AngelCode Scripting Library, or AngelScript as it is also known, is an extremely flexible cross-platform scripting library designed to allow applications to extend their functionality through external scripts. + +Besides that, AngelScript commonly behaves like C++ - for example, when it is statically typed. Just as in C++, when you declare a variable in AngelScript, you also must declare its types. In addition, AngelScript also implements its own version of pointers (called handles). It also aims to help users in writing its code, whether by disallowing certain operations or by assuming. More on that will be explained in later parts of the guide. + +Use cases for AngelScript vary heavily. It is much closer to pure engine code than VScript, meaning that you can achieve outputs not possible in VScript, such as programming in custom entities and custom commands. + +AngelScript's official documentation can be found here: [AS Official Docs](https://www.angelcode.com/angelscript/sdk/docs/manual/doc_script.html). + + +## What Can You Do With AngelScript +ngelScript allows for a closer connection to the internal engine code by having the engine provide various APIs to its internal classes. This allows you to do various things, such as creating custom entities, creating your own ConCommands and ConVars, making custom weapons - all things that aren't normally easy to do with VScript. + +While VScript (mainly) sits between entities and handles the interactions between them, AngelScripts sits in a level above, being able to *create* entities and define their behavior. + +--- + +## AngelScript in Strata Source + +### Client - Server Model +Before you write your first script, there is one more thing you need to know. Most engines, including the Source engine, operate on the client-server model. This means that client code is separate from the server code, even in singleplayer. When starting a map in singleplayer, you essentially create a one-player server that runs beside the client. This is very important to remember as AS code can be loaded on both. Some functionality will only be available on the server (such as entities) and some functionality will only be available on the client (such as Panorama/UI). + + +### Loading Code +Where should you place the files containing your code? +Each file that contains your code should end with the **.as** extension and be placed in the **code/** folder of your respective `Game` searchpath. Example locations would be `p2ce/custom/my-addon/code/` or just `p2ce/code/` (the latter is not recommended). +Code can also be placed inside the `code` folder of an addon created with the SDK Launcher. + +You may name your files however you'd like. You can create custom directories or you can place your files loosely - it all depends on what you're trying to achieve. In the long run, it's not important. What *is* important is where you place the "starting points". The engine will not attempt to load any files except for these 3 files placed **directly** in the **code/** folder: + +1. `init.as` - Will get loaded by server and client. +2. `sv_init.as` - Will only get loaded by the server. +3. `cl_init.as` - Will only get loaded by the client. + +### IDE and Testing Environment +It is suggested to use Visual Studio Code with the [AngelScript Language Server (sashi0034.angel-lsp)](https://marketplace.visualstudio.com/items?itemName=sashi0034.angel-lsp) extension. From there, you can open the `code/` folder of your choice as a project and begin development. +The engine compiles scripts on every map load (you can use the `reload` command to recompile the scripts). + +### Your First Script +You should now be ready to begin writing your very first program. For now, let's just print a Hello World message to the console. Though the code below may look foreign for now, don't be dissuaded! Place this code into `cl_init.as` as it is a client command. + +```cpp +[ClientCommand("HelloWorld", "")] +void MyCommand(const CommandArgs@ args) { + Msg("Hello world from AngelScript!\n"); // You can place your own text here! +} +``` + +Now, the only thing left to do now is launch the game, open the console, and execute the *HelloWorld* command. + +> ### TASK 1: +> Run the HelloWorld program mentioned above. + +## How To Test Out Your Code in a Basic Way +For now, you will need to know how to run your code so that you can complete the tasks given to you within this guide. +In `sv_init.as` include: +```cpp +[ServerCommand("CodeTest", "")] +void CodeTest(const Command@ args) { + // Here you can put your code +} +``` + +The code in this function will run whenever you run the `CodeTest` command in game. Remember to `reload` to see the changes! +The `Msg(string)` function will serve as a way to view your variables (like print or cout). Just type `Msg(a)` where *a* is your variable, and *a* will be printed to the console. +Remember to add `"\n"` to the input of Msg (or just call `Msg("\n");` after your message), otherwise everything will print in one line. To avoid having to do this, you can use the `Msgl(string)` which will automatically append an `"\n"` to the end of each message. + +> [!BUG] +> Some types such as `int` cannot be directly converted to string, and as such, you won't be able to put them directly into Msg(). +> > [!TIP] +> > In order to avoid this issue, you can append to an empty string. Just do `"" + a` and in most cases this will work: `Msg("" + a);` + +### Compilation Errors +Scripts will often report errors before they are ran, usually on map load. If you don't see your functionality (such as a command not being the console), scroll up and check the error. Additionally, you can use the first tip in the [tip section](#additional-tips) and then use `reload`. + + +## Additional Tips + +> [!TIP] +> Reading console output can be tiresome, as much more is happening in the console than just the script system. To overcome this problem, you can run `con_filter_text scriptsys; con_filter_enable 1` to filter out anything that is not the script system. diff --git a/docs/angelscript/guide/chapter2.md b/docs/angelscript/guide/chapter2.md new file mode 100644 index 00000000..ddbb00ca --- /dev/null +++ b/docs/angelscript/guide/chapter2.md @@ -0,0 +1,116 @@ +--- +title: Chapter 2 - Primitive Types, Declaration & Assignment +weight: 1 +--- + +# Chapter 2 - Primitive Types, Declaration & Assignment + +## What will you learn in this chapter +In this chapter you will learn about: +- [Primitive Types](#primitive-types), +- [Declaration and assignment of primitive types](#primitive-types), +- [Auto keyword](#auto-keyword), +- [Constants and the const keyword](#constants), +- [Integer size reference table](#integer-size-reference-table). + +> Unfortunately, in this chapter you won't learn anything really interesting, but this knowledge is crucial to continue further. Data types in general are a very extensive subject, but you don't need to know everything. This chapter is supposed to teach you how to handle primitive types in your script. + +> [!NOTE] +> This chapter won't cover every detail about any of data types, it is recommended you visit the [Data Types Section](../game/type) of the wiki for more information. +> Alternatively, you can find references on the [AS Official Documentation](https://www.angelcode.com/angelscript/sdk/docs/manual/doc_datatypes.html), however please note that Strata's wiki will be the most representative, some functionality might have been changed! + +--- + +## Primitive Types +Primitive types are the more "simpler" types, and are only implemented in the backend by the Strata Team inside the engine itself. These types include: `int`, `bool`, `float`, `double`, etc. + +> [!WARNING] +> It is assumed you already know about these data types from other languages (mainly C++). This subsection will only provide information relevant to AngelScript itself. + +### Declaration and assignment +Primitive types can easily get assigned and can be passed by primitive to functions (more on that later). +To create a primitive type you usually perform a declaration and an assignment, or both at once: +```cpp +int myInt; // Declaration +myInt = 20; // Assignment + +int myInt2 = 2; // Initialization +``` + +You can declare multiple variables of the same type at once: +```cpp +int myInt1, myInt2, myInt3; +``` + +Once declared, variables cannot change their type without redeclaration. This is not allowed: +```cpp +int myInt; +myInt = 3.2; // myInt is of type int, not float/double! +``` + +> ### TASK 1: +> 1. Create a program that will declare and assign variables of types `int`, `bool`, `double`, and then print them out to the console. +> 2. Do the same but use variable initialization. + +### Auto keyword +Although not recommended, the `auto` keyword will make the compiler automatically determine the data type of the variable: +```cpp +auto i = 1; // Will set type of i to integer +auto s = 3.14; // Will set type s to float +auto var = functionThatWillReturnAnObjectWithAVeryLongName(); + +// Handles (described in later chapters) can also be declared with auto +auto@ handle = @obj; +``` + +The `auto` keyword is not recommended for several cases. The main one of them is that you cannot immediately see the data type of a returned object especially from functions, like the one above. We don't know what that function will return. Another reason is that sometimes the compiler might guess wrong, especially in cases like integers, where you have multiple ways that `1` could have been described (e.g. int8/int16, both can describe `1`, even `bool` can). + +--- + +### Constants +Constant variables are variables that cannot change over the lifetime of the [variable scope](chapter3) they are created in. +You can define a constant variable using the `const` keyword: +```cpp +const int size = 31; +const auto w = true; // const also works with the auto keyword +``` + +Constants can be useful as a sort of configuration of the script itself. If you reuse a statically defined value you can instead define a global constant and then changing one value will change everything at once: +```cpp +const int MAX_SIZE = 16; + +int myint = 27; +my_func1(myint, MAX_SIZE); // A function that does something with myint, but also needs to have additional information +my_func2(myint, MAX_SIZE) // Another function that does something else with myint, but it also needs the same additional information +``` + +Constants are also a way to optimize your code. If you know that a variable won't change (or shouldn't change) after it's initialization, always make it a constant. +```cpp +bool function(int s, float i) { + const float value = s - i; + return i > value; +} +``` + +> ### TASK 2: +> Write a program that initializes a constant variable with the `auto` keyword, and then tries to change it after. Observe the compilation error in the console. + +--- + +### Integer size reference table +The table below shows the minimum and maximum values for each integer subtype (don't worry about remembering this, just remember that it exists here): +|Type|Short description|Minimum Value|Maximum Value| +|---|---|---|---| +|int8| Signed, 8 bits |-128 | 127 | +|int16| Signed, 16 bits |-32,768 | 32,767 | +|int| Signed, 32 bits |-2,147,483,648 | 2,147,483,647 | +|int64| Signed, 64 bits |-9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 | +|uint8| Unsigned, 8 bits, also represents characters (char) | 0 | 255 | +|uint16| Unsigned, 16 bits | 0 | 65,535 | +|uint| Unsigned, 32 bits | 0 | 4,294,967,295 | +|uint64| Unsigned, 64 bits | 0 | 18,446,744,073,709,551,615 | + +> [!TIP] +> The official AngelScript documentation mentions that the scripting engine has been mostly optimized for 32 bit datatypes (int/uint). Using these is recommended for the most part (unless you are dealing with numbers that don't fit into int/uint). + + diff --git a/docs/angelscript/guide/chapter3.md b/docs/angelscript/guide/chapter3.md new file mode 100644 index 00000000..9d8e12d0 --- /dev/null +++ b/docs/angelscript/guide/chapter3.md @@ -0,0 +1,163 @@ +--- +title: Chapter 3 - Statements, Expressions, Conditions & Variable Scope +weight: 2 +--- +# Chapter 3 - Statements, Expressions, Conditions & Variable Scope + + +## What will you learn in this chapter +In this chapter you will learn about: +- [Expression statements](#expression-statements), +- [Comparison operators](#comparison-operators), +- [Logic operators](#logic-operators), +- [If/else block](#ifelse-block), +- [Switch statement](#switch-statement), +- [Variable Scope](#variable-scope). + +> Statements, expressons, conditions and the variable scope are the foundation of every program or script. +--- + +## Basic statements + +Your code is like a recipe, and statements are the individual steps. + +Statements are a way to tell the script engine what it needs to do, we already used them in previous chapters, such as the assignment or declaration. + +### Expression statements +Any expression can be placed on a line as a statement. Examples of expressions include: +- Function call **()** operator - calls a function (more on functions later), +- Equals **=** operator - performs assignment, +- Add **+** operator - adds two values together, +- Substraction **-** operator - substracts two values from each other, +- Many more, such as **+=**, **-=**, **++**, etc. are available. More about them can be found in the [expression reference table](https://www.angelcode.com/angelscript/sdk/docs/manual/doc_expressions.html). + +Such statements need to end with the semicolon (`;`): +```cpp +b = a + b; +func(); +a += b; +``` + +AngelScript follows a specific instruction of operation order. Function calls are evaluated first bottom to top, then AS sticks to order of operations as specified in the [Operator Precedence](https://www.angelcode.com/angelscript/sdk/docs/manual/doc_operator_precedence.html) reference. + +You can force an order of operations by using parenthesis: +```cpp +float a = 1 + 1.0 / 2; // This will return 1,5 +float b = (1 + 1.0) / 2; // This will return 1 +``` + +> [!TIP] +> Order of how operators are evaluated for standard math operators such as **+**, **-**, **\***, **/**, etc. follow the standard Order of Operations. + +> ### TASK 1: +> Given `float a = 4; float b = 5;` Write a program that calculates the number c given by the equation: `c = (a - 2)^2 + (b + 1) / 2`. + + +### Comparison operators +Comparison operators are operators of which expressions evaluate to the `true` or `false` boolean values. An example of a comparsion operator is the equals (**==**) operator, which checks if the two values on boths sides of such operator are equal. Another type of a condition operator is the greater than operator (**>**), which checks if the value on the left side is greater than the value on the right side. For comparison operator reference please check the [expression reference table](https://www.angelcode.com/angelscript/sdk/docs/manual/doc_expressions.html). +```cpp +int a = 1; +int b = 2; +a == b; // Will return false, but it won't save the value anywhere, treat this as a whole: (a == b) + +b = 1; +bool result = a == b; // Result now stores the information if a and b were equal when it was defined. +``` + +### Logic operators +Logic operators are a way to combine comparison expressions in order to achieve one result: +- NOT - denoted as `!`, evaluates to true, if value is false and vice versa, +- AND - denoted as `&&`, evaluates to true, if both values are true, +- OR - denoted as `||`, evaluates to true, if even one of the values is true, else false if both are false, +- XOR - denoted as `^^`, evaluates to true, if and only if **one** of the values is true. + +```cpp +a && b; // AND +a && b || c; // A combination of AND and OR, a AND b is going to get evaluated first +a && (b || c); // You can use parenthesis to specify which operator should get evaluated first, here OR will get evaluated first +``` +> [!NOTE] +> Although AngelScript supports Python-like logic operator notation (and, or, ...) it is recommended to stick to the C-like notation. This is mainly because AS is much more similar to C in it's syntax, and also not every extension adding AS support for your IDE has support for the Python-like notation. + + +--- + +## Conditions +Conditions are a way to tell the engine to execute specific code only if a specific condition is met. For example, only add numbers if they are positive. +They should contain an expression that evalues to true or false, and they can be any sort of valid combination of comparison operators and logic operators, etc. + +### If/else block +The `if`/`else if`/`else` block is used to run specific code only on certain conditions. The `else if` and `else` are not required, but the block must start with an `if` statement. +```cpp +if ( a > 10 ) { // Condition 1 + // Run the code in here +} else if ( a < 10 ) { // Condition 2 + // If we haven't met condition 1, but have met condition 2, execute the code in here +} else if ( condition3 ) { + // We haven't met neither condition 1, nor condition 2, but we have met condition 3 +} else { + // If none of the conditions were met, execute this code +} +``` + +> ### TASK 2: +> Given two numerical values *a* and *b* (defined statically in your script) prints out an absolute value of their difference. + + +### Switch statement +The switch statement is a very useful tool for situations where you need to compare to a lot of different cases. It performs the *is equal* operation comparing a value to every value specified in case blocks. It is also much faster than a block of the `if`/`else if`/`else` statements. +```cpp +switch ( value ) { + case 0: + // Do if value == 0 + break; // Required keyword to go out of the switch block + + case 2: + case 3: + // Execute if value == 2 or value == 3 + break; + + default: + // Execute if neither cases were met +} +``` +> [!CAUTION] +> Each case requires a `break` statement after finishing code execution. This is because switch behaves more like the `goto` (C++) functionality, meaning that it doesn't stop executing code after finishing a specific case. The `break` statement will tell the code to go out of the `switch` block. This is also why in the upper example `case 2:` and `case 3:` can be used to both execute the same lines of code. + +> ### TASK 3: +> Given a string as a value (statically defined), write a program that would simulate a command-like behaviour using the switch statement. If the string is equal to: +> - "hello" - print "HelloWorld" to the console +> - "engine" - print "Strata Source" to the console +> - "name" - print "My name is Chell" to the console +> - on any other string - print "Command not recognized!" to the console + + +--- + +## Variable Scope + +Variable Scope determines which data can be accessed from where. In AngelScript the Variable Scope behaves exactly as the one in C++. +In general the Variable Scope makes programs use less memory by not holding expired (not useful anymore) information inside the memory, as an example: +```cpp +int number = 10; + +void my_func1() { + int my_number = 21; +} + +void my_func2() { + number = 20; // Success, number has been reassigned to 20 + my_number = 80; // Error, my_number has not been declared +} +``` +In this case my_number doesn't exist inside *my_func2*, it only exists inside *my_func1* and only for the duration of that function's execution. + +Statements such as `if`, `else`, `for`, `while`, `try`, etc. create local variable scopes each time, meaning that variables declared inside them cannot be accessed outside of them, contrary to how for example Python handles it (where scopes are only created inside functions). + +In AS, global variables are allowed, however: + +> [!NOTE] +> From the official documentation: *Variables of primitive types are initialized before variables of non-primitive types. This allows class constructors to access other global variables already with their correct initial value. The exception is if the other global variable also is of a non-primitive type, in which case there is no guarantee which variable is initialized first, which may lead to null-pointer exceptions being thrown during initialization.* + +> [!TIP] +> A good practice is to avoid global variables altogether, and use different means of sharing information between functions such as returning values or &out references (more on that in later chapters). \ No newline at end of file diff --git a/docs/angelscript/guide/chapter4.md b/docs/angelscript/guide/chapter4.md new file mode 100644 index 00000000..e1a33bf7 --- /dev/null +++ b/docs/angelscript/guide/chapter4.md @@ -0,0 +1,174 @@ +--- +title: Chapter 4 - Loops +weight: 3 +--- + +# Chapter 4 - Loops + + +## What will you learn in this chapter +In this chapter you will learn about: +- [While, do while loops](#while-do-while), +- [For loop](#for), +- [Foreach](#foreach), +- [Continue/Break keywords](#special-keywords). + +> Loops are a way to make the code repeat itself a certain amount of times, of which the amount of repetitions may vary depending on what is going on in the code. + +--- + +### Arrays - short introduction +> [!NOTE] +> This subsection is supposed to teach you the very basics of arrays, because next you will learn about loops, and loops are mostly useful for array manipulation. +> You won't learn in details what the array is and how to do operations on it, but you will learn how to create one and access its elements. + +An array is an ordered group of elements, of which there is a starting element and an element at the end. + +Code-wise it's a template object, as you need to specify of which data type its values will be. To create an array you can use the **{element, element2, ...}** assignment: +```cpp +array@ a = {0, 1, 2, 3, 4}; +array@ b = {true, false, false, true, false}; +array@ c = {.1, .3, .5}; +``` + +> [!NOTE] +> Since `array` and `dictionary` are value types, you initialize them as an object handles (the @ symbol). For now, just remember that you add that symbol after the type name, it will get explained later on. + +To access elements in an array you use the index operator **[]**, where `[i]` will access the i'th element of the array (counting from 0): +```cpp +a[3] // = 3 +b[1] // = false +b[0] // = .1 +``` + +More on the arrays will be talked about in later parts of this guide. + +--- + +## While, do while +The `while (expression)` loop will execute code until the expression evaluates to false: +```cpp +int a = 10; +while (a > 0) { + a--; // Decrement (substract one from a) each time the code executes + // Code in here will stop executing when a will be equal to 0 +} + +other_code(); // This will execute after the loop +``` +The `while` loop will not execute the code (even once) if the condition evaluates to false from the very start. + +A `do while` loop however, will first execute the code inside the loop and only *then* check if the condition is true to execute it once more: +```cpp +int a = 10; +do { + a--; +} while (a > 0); // Note the semicolon +``` + +> [!WARNING] +> It is possible to create a never ending loop, the easiest way is to do `while (true)`. Such loops are most of times an error in programming. However, these loops can be an intentional decision when **you are sure the loop will at some time stop executing**, either with the `break` statement (more on that in a bit) or other ways. + +> ### TASK 1: +> Write a program that will print out "Hello again!" to the console 10 times. + +## For +A `for` loop is an advanced version of the `while` loop. It takes 3 arguments in its statement - `for (statement1; statement2; statement3) {...}`: +- Statement 1 - gets executed before the loop runs (but in the loop's variable scope), often used to intialiaze a local indexing variable, such as `int i = 0;`. +- Statement 2 - is a condition for the execution of the loop, checked before the loop executes the code inside. +- Statement 3 - is executed after a successful code execution inside the loop (every time). + +An example of a `for` loop can be a loop that cycles through every character in a string: +```cpp +array@ numbers = {1, 1, 2, 3, 5, 8, 13}; +for (int i = 0; i < numbers.length(); i++) { // For every i until i is greater or equal to the array length (this will ensure i won't go out of bounds) + numbers[i] // Represents the i'th number in the array + // After executing code do i++ (add one to i), so we can access the next element +} +``` + +> [!TIP] +> Statements 1 and 3 in for loops can be skipped, as an example `for (;condition;)` is a valid form of a `for` loop, and so is `for (int a = 0;condition;)` etc. + +> ### TASK 2: +> Given an array of integers, write a program that will add all of these integers and print out the result. +> > [!NOTE] +> > Because of the [Variable Scope](chapter3/#variable-scope), you will need to define a variable to store the sum outside of the loop. + + + + +## Foreach + +A `foreach` loop can be used to perform code for each item in a container objects. Container objects are objects that store values of other data types, such as the `array` object or the `dictionary` object. Its structure `foreach (vars : container_object)` consists of two parts: where vars contains declarations of the variable names, such as `int val`, and the container object is the, well, container object. Some objects unpack more than one variable, such as the `dictionary` objects that unpacks the key and the appropriate value. + +```cpp +array@ integers = {1, 2, 3, 4}; +foreach (int i : integers) { + // Code here, where i will cycle through every value in integers +} + +dictionary@ mydict = { + {"key1", value1}, + {"key2", value2}, + {"key3", value3} +}; +foreach (auto value, auto key : mydict) {// NOTE: the order is flipped here, as compared to e.g. foreach in Squirrel (VScript), value goes first + // Loop through mydict +} + +foreach (auto value : mydict) {...} // It is also possible to just loop over one of the elements to unpack +``` + +> ### TASK 3: +> Write a program that will print out every element of a given array. + + +## Special keywords + +These are the special keywords that can be used inside loops. + +### Break statement +The `break` statement is a way to exit a loop execution early. Calling it will cause the program to abort loop execution and continue executing code after the loop. + +```cpp +int a = 10; +while (a > 0) { + if (a == 5) { + break; + } +} +// This loop will stop executing when a will be equal to 5 +``` + +### Continue statement +The `continue` statement will cause the loop to stop and go to the next element. + +```cpp +int sum = 0; +for(int i = 0; i < 10; i++) { + + if (i == 4) { // If i is equal to 4, we are skipping it + continue; + } + + // This code will not execute for i = 4 + sum += i; +} +``` + +### Nested loops and special keywords +Keywords like `break` and `continue` work on the bottom-most loop in nested code, meaning that if you have code like this: +```cpp +while (condition) { + for (int a = 5; a < 10; a++) { + + if (a > 5) { + break; // This will break of the for loop, not the while loop! + } + } +} +``` + +> ### TASK 4: +> Create a **while (true)** loop that adds all integers until 20. diff --git a/docs/angelscript/guide/chapter5.md b/docs/angelscript/guide/chapter5.md new file mode 100644 index 00000000..71d92f78 --- /dev/null +++ b/docs/angelscript/guide/chapter5.md @@ -0,0 +1,365 @@ +--- +title: Chapter 5 - Functions +weight: 4 +--- + +# Chapter 5 - Functions + +## What will you learn in this chapter +In this chapter you will learn about: +- [Declaring functions and calling functions](#syntax), +- [Calling methods on built-in objects](#calling-methods-on-objects), +- [Default parameters](#default-parameters), +- [References and passing variables by reference to functions (`&in`/`&out`)](#references---short-intro), +- [Returning references and when it can be done](#returning-references), +- [Function overloads](#function-overloads). + +> Functions are a way to split up the code into re-usable parts. + +--- + +## Functions - Basics + +### Syntax + +As you already know or not, functions are a way of implementing routines that operate on an input and produce a result. In Layman's terms, you give it some data, it processes the data and (may, but doesn't need to) give you an output. + +A function declaration consists of 3 main parts: *return value*, *function name*, and the *parameters*. +These follow pretty much the same syntax as C++: + +```cpp +// return_value func_name(parameters), +// examples: + +int myCoolFunction() { // This function returns an integer + ... + return integer_variable; +} + +void myFunction() { + ... + // No return statement + + // or return statement without a value (useful if you want to return early) + return; +} + +bool myFunction(int a, int b) { + ... + return bool_variable; +} +``` + +Each function **must** have a return statement in each of its "paths". What that basically means, is that whatever you do in your function, it will always end with a return statement. The only exception is the `void` return type (which means return nothing), in which you can skip the `return` keyword entirely, or use the `return;` statement when you want to exit the function early. + + +### Calling functions + +Calling functions in code is very simple, you use the **function call `()`** operator, `func(arguments)`. In it, you include every needed argument: + +> [!NOTE] +> ""Variables"" in a function declaration are called **parameters**, while ""variables"" in a function call are called **arguments**. + +```cpp +int sum(int a, int b) { // a, b are parameters + return a + b; +} + +int just5() { + return 5; +} + +int a = sum(1, 2); // 1, 2 are arguments + +a = sum(a, just5()); // just5 will get evaluated first, then its result will get passed to sum +// a = 5 +``` + +Calling a function is a statement, which means it can be freely used in expressions in every combination. You can treat `func(p)` as a value that you do operations with. + +### Calling methods on objects +Some objects such as `string` or `array` implement methods. For now, you can think of methods as functions that sit inside the object (variable), and operate on that object. You can invoke them by using the `.` operator and then the function call. +```cpp +string mystr = "ABC"; + +mystr.length(); // Returns the length of this string (3) +``` + +For a list of available methods per each type please refer to the [types section](../game/type) of this wiki. +> [!NOTE] +> Primitive types (`int`, `float`, `bool`, etc.) don't implement any methods. + +### Recursiveness + +Like in any other language, a function can call itself. This is function is then called a *recursive* function. + +### Calling template functions + +Templates are a way of generalizing code for multiple types. To use a template function, you specify the type(s) in the angle brackets, like so: +```cpp +function_name(argument1, argument2, ...); +``` + +These functions are not very common, but here's an example of one (`util::CreateEntityByNameT`): +```cpp +CBaseEntity@ script_ent = util::CreateEntityByNameT("logic_script"); +CBaseAnimating@ model_ent = util::CreateEntityByNameT("prop_dynamic"); +``` + +--- + +## Parameters + +Function parameters in AngelScript can be a bit confusing, since AS has custom keywords and custom behaviors for different types of parameters. + +### Default parameters +Sometimes you want to add additional functionality to your function, but for most cases you already know what it should do, although you still want to include a customizable option for fine-tuning. You can do that by default parameters. + +Each parameter can have a default value assigned to it, like so: +```cpp +void myFunc(int a = 5, int b = 1) {...} +``` + +This function can be called with *0*, *1*, and *2* arguments, and each call will be valid. +Calling it with 0 arguments will mean that `a` will be set to `5`, and `b` to `1`. Calling it with one argument will set a to that arguments value and so on. +```cpp +myFunc(); // a = 5, b = 1 +myFunc(2); // a = 2, b = 1 +myFunc(2, 5); // a = 2, b = 5 +``` + +> [!NOTE] +> It is currently not possible to explicitly set each parameter to a specific argument. In Python for example, doing `myFunc(b=2)` is allowed and will set `b` equal to `2`, however this is not the case in AngelScript. +> > [!TIP] +> > You can use [function overloads](#function-overloads) to overcome this issue. + +### Constant parameters + +Constant parameters work just like constant variables. If declare a certain parameter constant, you won't be able to change it in any way. +```cpp +void myFunc(const int a, const bool y = true) // Default parameters can also be constants +``` + +One important note is that declaring a const parameter will make the compiler not copy the object (if it ensures the object's lifetime). More on that will be in the next chapters. + +> ### TASK 1: +> Create a function that computes the nth number of the fibonnaci sequence. It should take uint as the parameter (n) and return an uint (the number). You can tackle this problem recursively (using recursion) or iteratively (using a loop). It is recommend to try out both. + +### References - short intro +Before we delve into the next subchapter, you need to know what *references* are. In each computer, variables are stored in memory. You can visualize computers memory as a some sort of a box with labels. Each label has some space that it describes, and there can be an item in each label. Such items are our variables, and these labels are memory addresses. In such way, the computer knows where to look for these variables when it needs to find them. + +References are just the labels we have been comparing to, they *are* the address of the variable they correspond to. + +They are denoted with the **&** symbol. Conceptually: +```cpp +string mystring = "lorem ipsum"; +&mystring // Memory address of mystring +``` + +In angelscript you cannot directly manipulate references, but you can do many useful things when you combine functions and references. The AngelScript compiler will automatically manage referencing (getting a variables adress) and dereferencing (looking up a variable from an adress). + +### Reference parameters +Functions can be set to use references as parameters. + +In the examples shown above every argument was **copied**. Here's a better example: +```cpp +void func(int c) {...} + +int a = 1; +func(a); +``` +In this example, before `c` gets assigned a value from `a`, the value of `a` gets copied first, and only after that the assignment occurs. This happens, so that doing any operations on `c` in `func` will not cause `a` outside the function to change in any way. + +However, passing by reference changes that mechanism. Since now, the thing that gets copied is the memory address, not the actual variable value. Meaning that if we were to pass by reference in `func` above, doing any operation such as `c = 5;` would cause `a` to change accordingly (a = 5). + +Telling the compiler that you want to pass by reference gets done in the function parameters declaration, like so: +```cpp +void func(int& c) // This is a pass by reference +``` + +No special syntax for calling is needed: +```cpp +int a = 1; +func(a); // a gets passed by reference +``` + +AngelScript implements more functionality to passing by reference, and that includes 2 options: + +#### &in +This marks the parameter as an input to the function. This option provides little to no benefit as to just passing by value (copying), as the compiler still has to ensure the object won't get modified outside the function, and the only way to do that is to make a copy. + +> [!TIP] +> Combining `&in` with `const` can however, yield a way more optimized code. `&in` should almost always be used whenever you are using a `const` parameter. + +> [!WARNING] +> Primitve types should not be passed with `&in`, as the memory address still has to be copied over, resulting in the same hit of performance (or worse!) as just copying the value itself. + +#### &out +This option specifies that this parameter is an output of a function. This is especially useful whenever you have functions that need to have multiple output values. At the start of a function's execution, this reference will point to an uninitialized variable. After the function returns, the value assigned to this variable will be copied over to the appropriate argument. + +Example usage of passing by reference of all 3 options: +```cpp +// Example of &in usage +void PrintMessage(const string&in msg) { // This will make the compiler try to not copy the argument when calling the function, as we are not modifying it in any way. + Msg(msg + "\n"); // Convenience function that prints the message with \n appended +} + +// Example usage of &out +bool WholeDivision(int a, int b, int&out result, int&out rest) { + // Calculates the whole part of a/b and the rest + // Returns true if the operation can be done. + if (b == 0) { + return false; // We cannot divide by zero + } + + result = a / b; + rest = a % b; + + return true; +} + + +int myresult, myrest; +WholeDivision(10, 3, myresult, myrest); //This will set myresult and myrest to the appropriate (3 and 1 respecitvely). +``` + +#### &inout / & +This option specifies that this parameter will be passed by reference in both directions. Meaning, the argument will not be copied, and also any changes made to this variable will result in a modified state of the argument outside the function. + +> [!NOTE] +> `&inout` or `&` are **not** supported for primitive types. + + +--- + +## Returning references + +Functions can also *return* references. Meaning that they return an address to an object, rather than the object itself. In previous examples we have discussed functions that return by value, meaning that the value of the variable that gets returned, gets copied to a temporary location and then gets "transfered" over to the variable outside the function: +```cpp +int func(int a) { + return a * 2; +} + +int b; +b = func(2); // Result of func(2) gets stored in a temporary location and then copied over to b. + +func(2) = 1; // This will not work. +``` + +Returning references works in a different way, we return an address, that means the actual value of the variable never gets copied which saves on performance. Additionally, it allows you to do operations on the return value of a function. To declare a function that returns a reference, you append the `&` symbol at the end of the type name in the return type. + +Before we overview examples, there is one more thing to discuss about returning references. Not every variable can get it's reference returned. In general, variables that don't exist outside the function will not be able to get returned by reference, because they will get erased once the code gets out of the function. + +#### 1. References to global variables are allowed. +Returning references to global variables is allowed, because the variable won't get destroyed outside the function. Example: +```cpp +int a = 1; + +int& addToA(int b) { + a + b; + return a; // Like in reference parameters, no additional syntax is needed. +} + +//This will allow us to do something like: +addToA(1) = 3; // We add 1 to a, but then we change a to be equal to 3. +``` + +#### 2. References to class members and `this` are allowed. +> [!NOTE] +> This information will be useful once we get to custom classes and reference types, so if you don't know what these are you can skip this for now. + +References to class members (properties) and to ourselves (`this`) are allowed to be returned by methods. + +```cpp +class myclass { + int myvar; + + int& GetMyVarRef() { + return this.myvar; + } + + myclass& GetMe() { // Note: this will automatically translate to myclass@& (reference to the handle of myclass) + return this; + } +} +``` + +#### 3. Returning a reference to a local variable is not allowed. +Returning a reference to a local variable is not allowed, this is because the variable will not exist after the function returns. +```cpp +int& myFunc() { + int a = 1; + return a; // a will not exist outside of myFunc, this is not allowed +} +``` + +#### 4. Returning a reference to a deferred parameter is not allowed. +Values passed by reference into a function cannot be returned by reference. This is because AS does additional cleanup after the function returns, hence why there is no guarantee that an object passed by `&in`/`&out` will exist after the function returns. + +```cpp +int& func(int a&in ) { + return a; // This is not allowed +} +``` + +> ### TASK 2: +> Create a function that splits a string into two same-length parts. It should take a string and return a boolean if the string can be split (if the strings length is not divisible by two you cannot create two equal-length parts), and it should also return these two parts (use `&out`). + +--- + +## Function overloads +Function overloading is a very powerful concept, as it allows you to declare a function multiple times, each time with a different set of parameters. The compiler will then attempt to choose the best "fit" for which exact function to call (the criteria of how it does so are available on the [official documentation](https://www.angelcode.com/angelscript/sdk/docs/manual/doc_script_func_overload.html)). + +This is mainly used for functions that can accept multiple combinations and types of parameters, but produce a similar result. +```cpp +void myFunc(int a) {...} +void myFunc(string a) {...} + +myFunc(10); // Will call the first option +myFunc("a"); // Will call the second option +myFunc(10.5); // Will call the first option (but float will get converted to int) +myFunc(false); // Will cause an error since none of the options specify bool as a parameter +``` + +Default parameters are also allowed to be used in overloading, but you have to be careful whilst doing so. If you define your function wrong, the compiler will not be able to decide whether it should use an overload or use a default parameter. + +```cpp +void myFunc(int a, int b = 2) {...} +void myFunc(int a) {...} + +myFunc(1, 3); // Will work, since there is only one option. +myFunc(1); // Will not work, since the compiler doesn't know which option to choose (should it use the first and set the default parameter or should it use the second?) + +void myFunc(string a) {...} +void myFunc(int a, string c = "C") {...} // Same goes for different types of default parameters + +myFunc("A"); // Will work, there is only one option +myFunc(1); // Now there are 3 options to choose from and none are more important +myFunc(1, "A"); // Will work +``` + +> [!WARNING] +> Different return types are allowed for overloads, e.g. one function can return an int, whilst other can return a string (the auto keyword is useful here); however the compiler will not take the return type as a criteria for deciding which overload to use. + +> ### TASK 3: +> In the default parameters section there was a problem mentioned about how you cannot explicitly set custom parameters. Given a function: +> ```cpp +> int printXTimes(string msg, string end = "\n", int x = 1) { +> for (int i = 0; i < x; i++) { +> Msg(msg + end); +> } +> } +> ``` +> Find a way to use it to print 10 times the message "CONSOLE SPAM!" **without specifying a value for the `end` parameter!** +> > [!TIP] +> > You can call an overload to a different function in an overloaded function: +> > ```cpp +> > void myFunc(int a) {...} +> > +> > void myFunc(int a, int b) { +> > myFunc(a); +> > } +> > ``` + +> [!NOTE] +> If you completed the task above, congratulations! However, please note that this way of solving that problem is only viable when your default parameters have different types, because if they don't, the overload will not work. \ No newline at end of file diff --git a/docs/angelscript/guide/chapter6.md b/docs/angelscript/guide/chapter6.md new file mode 100644 index 00000000..c6e5e121 --- /dev/null +++ b/docs/angelscript/guide/chapter6.md @@ -0,0 +1,80 @@ +--- +title: Chapter 6 - Value Types +weight: 5 +--- + + +# Chapter 6 - Value Types + +## What will you learn in this chapter +In this chapter you will learn about: +- [Value types](#value-types---short-introduction) +- [Constructors](#constructors), +- [Value type initialization](#initializing-a-value-type), +- [Template value types initialization](#initializing-template-value-types) + +> Value types are a step above primitive types, basically. + +--- + +## Value types - short introduction +Value types are types that behave a bit differently in AngelScript compared to primitives. They are in some ways similar to primitive types mentioned before, however the main differences are: +- Although it might not always be the case, value types take up (much) more memory, +- They support object handles, and should be passed via them, +- They have methods, meaning functions that are bound to their type, +- They support the `&in` and `&inout` passing by reference in functions. + +One example of a value type is the `Vector` type. + +You can easily distinguish value types from primitive types based on a simple rule. Value types are described as literals, such as `1`, `true`, `3.14`, etc. +Whenever you see a literal, you are **sure** that this literal represents a **specific** value. However, when you see a value type used in code, you can be unsure of the value it represents, for example, `1` represents the number one, but there is no guarantee what `Vector()` represents. It can represent a 0 vector, but it can also be anything. There are also no literals that would represent any value type (one might suggest an example of: `const Vector ZERO_VEC(0, 0, 0);`, but that would be a constant global variable, not a literal). + +> [!NOTE] +> Value types can only be defined inside the application itself, you cannot create your own value types in AngelScript. User created types are called *reference types*, more on that in further chapters. + +## Using value types + +### Constructors +Constructors are functions that are ran on value type initialization, when an object gets created. They are often overloaded, meaning that you can create an object using different arguments, different types etc. Each type can have their own constuctors defined, thus you should refer to the each type's documentation on the constructors available. + +As an example, the `Vector` type has 3 different constructors: +```cpp +Vector(); // Calls the default constructor, meaning no arguments are passed +Vector(float x, float y, float z); // Constructs vector from 3 floats, respectively x, y, z +Vector(const Vector&in vec); // So-called copy constructor, constructs copying data from another vector +``` + +### Initializing a value type + +Initializing a value type is done by using parenthesis, after the variable name, like so: + +```cpp +Vector v1(1, 2, 3); // Creates a vector v1 +Vector v2(v1); //Creates a vector v2, copying data from v1 +``` + +> [!CAUTION] +> #### Common mistake - initializing with the assign operator. +> It is a common mistake to initialize an object using the assign operator, like so: +> ```cpp +> Vector v1 = Vector(1, 2, 3); +> ``` +> This is, indeed, a valid (in the language sense) method to initialize, although this should be avoided if possible. This is because, underneath, what the server is doing is: +> 1. Creating the object `Vector(1, 2, 3);` +> 2. Creating the `v1` Vector using the default constructor. +> 3. Calling the assign operator on v1, using data from the right side of the operator +> 4. Deleting the right object (`Vector(1, 2, 3)`) +> +> **This is much more inefficient than just calling the appropriate constructor (which would perform only one of the operations listed above!).** + + +#### Initializing template value types +Sometimes objects are described with a template, such as the `array` object. Because the `array` class is supposed to be versatile, it can support different types of data for it's values; you can have an array of integers, an array of floats, an array of strings, etc. There is no need to re-create the array class for each and every available data type, as this is where the template functionality is used for. + +When declaring an array you need to specify the data type of its values, like so: +```cpp +array@ string_array = {"string1", "string2", "string3"}; // Create an array of strings +array@ myArray = {1, 2, 3, 4}; // Create an array of integers +// Or, by using a constructor +array@ myArray2(10, 5); // Array: {10, 10, 10, 10, 10} +``` diff --git a/docs/angelscript/guide/chapter7.md b/docs/angelscript/guide/chapter7.md new file mode 100644 index 00000000..6fba37ef --- /dev/null +++ b/docs/angelscript/guide/chapter7.md @@ -0,0 +1,141 @@ +--- +title: Chapter 7 - Object Handles +weight: 6 +--- + +# Chapter 7 - Object Handles + +## What will you learn in this chapter +In this chapter you will learn about: +- [Object handles](#object-handles) +- [Object handle declaration](#declaration), +- [Object handle expressions](#expressions), +- [The Initialization Problem](#the-initialization-problem), +- [Handle reference counting](#reference-counting), +- [Object handle usage in functions](#handles-and-functions) + +> Object handles are like smart pointers from C++, they don't actually hold an object themselves, rather they hold an address in memory (reference) that can be used to locate the object they point to. + +--- + +## Object handles +These are objects that hold the address of an object, rather than the object itself. Meaning that by using object handles, you are manipulating the information about addresses of objects that are somewhere else, not ""in"" the variable itself. + + +## Declaration +An object handle is declared by appending the **@** sign after the data type name, e.g.: +```cpp +type@ handle; +// Or more explicitly: +type@ handle = null; +``` +This code will create a handle of type `type` and point it to null (meaning that it doesn't actually point anywhere). + +> [!CAUTION] +> It is not guaranteed that handles will actually point to valid data. Handles initialized like the one above point nowhere, and trying to perform any operation on them (such as calling methods) will cause an exception. + +> [!NOTE] +> Primitive types don't support object handles. + +You can access the handle of any reference type by prepending the **@** symbol to the variable: +```cpp +type my_object; +@my_object; // This is a handle to my_object + +type@ objhandle = @my_object; // Store the object handle in a handle variable +``` + +## Expressions +In expressions, object handles are treated *almost always* exactly the same as object variables themselves, which is something very specific to the AngelScript language. This means that: +```cpp +type my_object; +type@ my_handle = @my_object; + +// Calling methods can be done like so (both ways are correct) +my_handle.Method(); // In C++, you would need to use the -> operator here, but this is not the case with AngelScript. +my_object.Method(); +``` +In most of times the compiler will automatically know what you are trying to do, however, in order to explicitly call a handle operation you have to **prepend the variable name with the handle symbol (@)**. + +```cpp +type obj1; +type@ objhandle; + +objhandle = @obj1; // This will not work, and will make the script not compile. +@objhandle = @obj1; // This is a proper handle assignment, @objhandle gets set to point to obj1. +@objhandle = obj1; // This will also work because of object variables being handles internally, but is confusing to read, and so - not recommended. +``` + +--- + +## The Initialization Problem + +As explained in chapter 6, initializing value types with the assign operator is well performant. +As an example, let's assume the `object` class implements opAssign (assignement operator method), doing: +```cpp +type my_object = 10; +``` + +Will result in the previously explained behaviour, which is **not recommended**, however, doing: + +```cpp +type@ my_object = 10; +// more specific example: +Vector@ vec_handle = @Vector(1, 2, 3); +// or +array@ array_handle = {1, 2, 3}; +``` +**Is fine to do**, because here an object gets created once, and assignment is done on the object handle, not the object itself! +This doesn't result in so many calls being made, because that calls the internal opAssign method (which should return a reference to the `type` type (us)), and so, we are actually doing a handle assignment (that assigns the handle to the same object, but in which opAssign has modified the internal properties). This is a completely valid way of declaring and initializing a value type. This code will call the default constructor, then opAssign(10). It depends on the implementation, but the performance hit here should be marginal (mainly because we're doing way less memory writes/reads). + +--- + +## Reference counting + +Object handles are reference counted, meaning that if somewhere in the memory, exists a handle to an object, it is safe to assume that object will **always** be accessible, and **will not** be removed after exiting from the variable scope it was created in. Objects are only removed from memory when all handles to them have been removed first. + +```cpp +// Returns a vector with coordinates [1, 2, 3] +Vector@ MagicVector() { + // Create the vector + Vector v1(1, 2, 3); + + //Return the handle + return @v1; +} + +... { + + Vector@ magic_vector = MagicVector(); + + // v1 object created in MagicVector has not been removed! It is safe to use magic_vector + float magic_vector_length = magic_vector.length(); // = 3.74... + + magic_vector = null; + // Since this was the only handle pointing to the v1 object, it got deleted. + +} +``` + +This gets especially useful when initializing reference types (the most advanced of data type), because you can initialize them directly to a handle: +```cpp +my_type@ my_handle = @my_type(...); +``` +There is no need to separately intialize my_type to a variable (`my_type my_obj(...);`). + + +## Handles and functions. + +In this regard, handles behave very similarly to primitives. You can pass them as arguments, specify them as parameters, return them, etc... + +```cpp +void scale(Vector@ v1_handle, const int factor) { + v1 *= factor; +} +``` +> [!NOTE] +> In the example above, the object passed with the handle **will** get modified outside the function. Here what gets copied is the handle, **not** the object underneath! + +> [!NOTE] +> Handles also support passing by reference, meaning that specifying e.g. `Vector@&out` will be valid. +> #### TODO: Do the same restrictions as for primitives (no &in) apply? \ No newline at end of file diff --git a/docs/angelscript/guide/meta.json b/docs/angelscript/guide/meta.json new file mode 100644 index 00000000..fa31d875 --- /dev/null +++ b/docs/angelscript/guide/meta.json @@ -0,0 +1,4 @@ +{ + "title": "Beginner's Guide", + "weight": 0 +}