diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index be6ed38..179c084 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,6 +6,7 @@ variables: before_script: - rm Gemfile.lock + - bundle install test: stage: test @@ -21,10 +22,8 @@ test: pages: stage: deploy interruptible: true - before_script: - - rm Gemfile.lock script: - - bundle exec jekyll build -d public + - bundle exec jekyll build -d public --baseurl /minetest_modding_book artifacts: paths: - public diff --git a/Gemfile b/Gemfile index 1f50fb4..c26845e 100644 --- a/Gemfile +++ b/Gemfile @@ -6,4 +6,5 @@ gem "webrick" group :jekyll_plugins do gem "jekyll-sitemap" gem "jekyll-redirect-from" + gem "jekyll-sass-converter", "~> 2.0" end diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7d4f96c --- /dev/null +++ b/LICENSE @@ -0,0 +1,427 @@ +Attribution-ShareAlike 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-ShareAlike 4.0 International Public +License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-ShareAlike 4.0 International Public License ("Public +License"). To the extent this Public License may be interpreted as a +contract, You are granted the Licensed Rights in consideration of Your +acceptance of these terms and conditions, and the Licensor grants You +such rights in consideration of benefits the Licensor receives from +making the Licensed Material available under these terms and +conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + l. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + m. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + including for purposes of Section 3(b); and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/_en/basics/getting_started.md b/_en/basics/getting_started.md index aa814a7..73ddd31 100644 --- a/_en/basics/getting_started.md +++ b/_en/basics/getting_started.md @@ -12,18 +12,18 @@ redirect_from: ## Introduction Understanding the basic structure of a mod's folder is an essential skill when -creating mods. +creating mods. In this chapter, you'll learn about how modding in Minetest works +and create your first mod. - [What are Games and Mods?](#what-are-games-and-mods) - [Where are mods stored?](#where-are-mods-stored) -- [Mod Directory](#mod-directory) -- [mod.conf](#modconf) - - [Dependencies](#dependencies) +- [Creating your first mod](#creating-your-first-mod) + - [Mod directory](#mod-directory) + - [mod.conf](#modconf) + - [init.lua](#initlua) + - [Summary](#summary) +- [Dependencies](#dependencies) - [Mod Packs](#mod-packs) -- [Example](#example) - - [Mod Folder](#mod-folder) - - [init.lua](#initlua) - - [mod.conf](#modconf-1) ## What are Games and Mods? @@ -53,7 +53,7 @@ and is applicable for both game developers and modders. Each mod has its own directory where its Lua code, textures, models, and -sounds are placed. Minetest checks in a number of different locations for +sounds are placed. Minetest checks in several different locations for mods. These locations are commonly called *mod load paths*. For a given world/save game, three mod locations are checked. @@ -78,54 +78,91 @@ mod will be loaded in place of the earlier mod. This means that you can override game mods by placing a mod with the same name in the global mod location. -## Mod Directory +## Creating your first mod -![Find the mod's directory]({{ page.root }}/static/folder_modfolder.jpg) +### Mod directory -A *mod name* is used to refer to a mod. Each mod should have a unique name. -Mod names can include letters, numbers, and underscores. A good name should -describe what the mod does, and the directory which contains the components of a mod -must have the same name as the mod name. -To find out if a mod name is available, try searching for it on +Go to the global mods directory (About > Open user data directory > mods) and +create a new folder called "mymod". `mymod` is the mod name. + +Each mod should have a unique *mod name*, a technical identifier (id) used to +refer to the mod. Mod names can include letters, numbers, and underscores. A +good name should describe what the mod does, and the directory that contains +the components of a mod must have the same name as the mod name. To find out if +a mod name is available, try searching for it on [content.minetest.net](https://content.minetest.net). mymod - ├── init.lua (required) - Runs when the game loads. - ├── mod.conf (recommended) - Contains description and dependencies. - ├── textures (optional) - │ └── ... any textures or images - ├── sounds (optional) - │ └── ... any sounds - └── ... any other files or directories + ├── textures + │ └── mymod_node.png files + ├── init.lua + └── mod.conf -Only the init.lua file is required in a mod for it to run on game load; +Mods only require an init.lua file; however, mod.conf is recommended and other components may be needed depending on the mod's functionality. -## mod.conf +### mod.conf + +Create a mod.conf file with the following content: + +``` +name = mymod +description = Adds foo, bar, and bo. +depends = default +``` This file is used for mod metadata including the mod's name, description, and other information. -For example: +### init.lua - name = mymod - description = Adds foo, bar, and bo. - depends = modone, modtwo +Create an init.lua file with the following content: -### Dependencies +```lua +print("This file will be run at load time!") + +minetest.register_node("mymod:node", { + description = "This is a node", + tiles = {"mymod_node.png"}, + groups = {cracky = 1} +}) + +minetest.register_craft({ + type = "shapeless", + output = "mymod:node 3", + recipe = { "default:dirt", "default:stone" }, +}) +``` + +The init.lua file is the entrypoint to a mod, and runs when the mod is loaded. + + +### Summary + + +This mod has the name "mymod". It has two text files: init.lua and mod.conf. The +script prints a message and then registers a node and a craft recipe – these +will be explained later on. There's a single dependency, the +[default mod](https://content.minetest.net/metapackages/default/), which is +usually found in Minetest Game. There is also a texture in textures/ for the +node. + + +## Dependencies A dependency occurs when a mod requires another mod to be loaded before itself. -One mod may require another mod's code, items, or other resources to be available -for it to use. +One mod may require another mod's code, items, or other resources to be +available for it to use. There are two types of dependencies: hard and optional dependencies. Both require the mod to be loaded first. If the mod being depended on isn't available, a hard dependency will cause the mod to fail to load, while an optional dependency might lead to fewer features being enabled. -An optional dependency is useful if you want to optionally support another mod; it can -enable extra content if the user wishes to use both the mods at the same time. +An optional dependency is useful if you want to optionally support another mod; +it can enable extra content if the user wishes to use both the mods at the same +time. Dependencies are specified in a comma-separated list in mod.conf. @@ -148,43 +185,3 @@ a player, but don't want to make them download each one individually. Please note that a modpack is not a *game*. Games have their own organisational structure which will be explained in the Games chapter. - -## Example - -Here is an example which puts all of this together: - -### Mod Folder - mymod - ├── textures - │ └── mymod_node.png files - ├── init.lua - └── mod.conf - -### init.lua -```lua -print("This file will be run at load time!") - -minetest.register_node("mymod:node", { - description = "This is a node", - tiles = {"mymod_node.png"}, - groups = {cracky = 1} -}) - -minetest.register_craft({ - type = "shapeless", - output = "mymod:node 3", - recipe = { "default:dirt", "default:stone" }, -}) -``` - -### mod.conf - name = mymod - descriptions = Adds a node - depends = default - -This mod has the name "mymod". It has two text files: init.lua and mod.conf. The -script prints a message and then registers a node and craft recipe – these will -be explained later on. There's a single dependency, the -[default mod](https://content.minetest.net/metapackages/default/), -which is usually found in Minetest Game. There is also a texture in textures/ -for the node. diff --git a/_en/basics/lua.md b/_en/basics/lua.md index e0188b6..71f17c4 100644 --- a/_en/basics/lua.md +++ b/_en/basics/lua.md @@ -9,21 +9,39 @@ redirect_from: /en/chapters/lua.html ## Introduction -In this chapter we'll talk about scripting in Lua, the tools required -to assist with this, and some techniques which you may find useful. +In this chapter, you'll learn about scripting in Lua, the tools required +to help with this, and some techniques that you may find useful. -- [Code Editors](#code-editors) -- [Coding in Lua](#coding-in-lua) - - [Program Flow](#program-flow) - - [Variable Types](#variable-types) - - [Arithmetic Operators](#arithmetic-operators) - - [Selection](#selection) - - [Logical Operators](#logical-operators) - [Programming](#programming) + - [Coding in Lua](#coding-in-lua) +- [Code Editors](#code-editors) - [Local and Global Scope](#local-and-global-scope) - [Locals should be used as much as possible](#locals-should-be-used-as-much-as-possible) - [Including other Lua Scripts](#including-other-lua-scripts) + +## Programming + +Programming is the action of taking a problem, such as sorting a list +of items, and turning it into steps that a computer can understand. +Teaching you the logical process of programming is beyond the scope of this book; +however, the following websites are quite useful in developing this: + +* [Codecademy](http://www.codecademy.com/) is one of the best resources for + learning to write code. It provides an interactive tutorial experience. +* [Scratch](https://scratch.mit.edu) is a good resource for starting from + absolute basics, and learning the problem-solving techniques required to program. + It's great for children and teenagers. +* [Programming with Mosh](https://www.youtube.com/user/programmingwithmosh) is + a good YouTube series to learn programming. + +### Coding in Lua + +It's also beyond the scope of this book to teach Lua coding. +The [Programming in Lua (PiL)](https://www.lua.org/pil/contents.html) book is an +excellent introduction to Lua programming. + + ## Code Editors A code editor with code highlighting is sufficient for writing scripts in Lua. @@ -54,156 +72,36 @@ Functions which come with Lua by default, such as `table.insert`, are also highl Commonly used editors which are well-suited for Lua include: -* [VSCode](https://code.visualstudio.com/) - +* [VSCode](https://code.visualstudio.com/): open source (as Code-OSS or VSCodium), popular, and has - [plugins for Minetest modding](https://marketplace.visualstudio.com/items?itemName=GreenXenith.minetest-tools). -* [Notepad++](http://notepad-plus-plus.org/) - Windows-only -* [Atom](http://atom.io/) + [plugins for Minetest](https://marketplace.visualstudio.com/items?itemName=GreenXenith.minetest-tools). +* [Notepad++](http://notepad-plus-plus.org/): simple, Windows-only Other suitable editors are also available. -## Coding in Lua - -### Program Flow - -Programs are a series of commands that run one after another. We call these -commands "statements." Program flow is how these statements are executed, and -different types of flow allow you to skip or jump over sets of commands. - -There are three main types of flow: - -* Sequence: runs one statement after another, with no skipping. -* Selection: skips over sequences depending on conditions. -* Iteration: repeats the same statements until a condition is met. - -So, what do statements in Lua look like? - -```lua -local a = 2 -- Set 'a' to 2 -local b = 2 -- Set 'b' to 2 -local result = a + b -- Set 'result' to a + b, which is 4 -a = a + 10 -print("Sum is "..result) -``` - -In this example, `a`, `b`, and `result` are *variables*. Local variables are -declared by using the `local` keyword, and then given an initial value. Local -will be discussed later, because it's part of a very important concept called -*scope*. - -The `=` sign means *assignment*, so `result = a + b` means set the value of -`result` to the value of `a + b`. Variable names can be longer than one -character, as seen with the `result` variable. It's also worth noting that, like -most languages, Lua is *case-sensitive*; `A` is a different variable to `a`. - - -### Variable Types - -A variable will be only one of the following types and can change type after an -assignment. -It's good practice to make sure a variable is only ever nil or a single non-nil type. - -| Type | Description | Example | -|----------|---------------------------------|----------------| -| Nil | Not initialised. The variable is empty, it has no value | `local A`, `D = nil` | -| Number | A whole or decimal number. | `local A = 4` | -| String | A piece of text. | `local D = "one two three"` | -| Boolean | True or False. | `local is_true = false`, `local E = (1 == 1)` | -| Table | Lists. | Explained below. | -| Function | Can run. May require inputs and may return a value. | `local result = func(1, 2, 3)` | - -### Arithmetic Operators - -Operators in Lua include: - -| Symbol | Purpose | Example | -|--------|----------------|---------------------------| -| A + B | Addition | 2 + 2 = 4 | -| A - B | Subtraction | 2 - 10 = -8 | -| A * B | Multiplication | 2 * 2 = 4 | -| A / B | Division | 100 / 50 = 2 | -| A ^ B | Powers | 2 ^ 2 = 22 = 4 | -| A .. B | Join strings | "foo" .. "bar" = "foobar" | - -Please note that this is not an exhaustive list; it doesn't contain every -possible operator. - -### Selection - -The most basic method of selection is the if statement. For example: - -```lua -local random_number = math.random(1, 100) -- Between 1 and 100. -if random_number > 50 then - print("Woohoo!") -else - print("No!") -end -``` - -This generates a random number between 1 and 100. It then prints "Woohoo!" if -that number is bigger than 50, and otherwise prints "No!". - - -### Logical Operators - -Logical operators in Lua include: - -| Symbol | Purpose | Example | -|---------|--------------------------------------|-------------------------------------------------------------| -| A == B | Equals | 1 == 1 (true), 1 == 2 (false) | -| A ~= B | Doesn't equal | 1 ~= 1 (false), 1 ~= 2 (true) | -| A > B | Greater than | 5 > 2 (true), 1 > 2 (false), 1 > 1 (false) | -| A < B | Less than | 1 < 3 (true), 3 < 1 (false), 1 < 1 (false) | -| A >= B | Greater than or equals | 5 >= 5 (true), 5 >= 3 (true), 5 >= 6 (false) | -| A <= B | Less than or equals | 3 <= 6 (true), 3 <= 3 (true) | -| A and B | And (both must be correct) | (2 > 1) and (1 == 1) (true), (2 > 3) and (1 == 1) (false) | -| A or B | either or. One or both must be true. | (2 > 1) or (1 == 2) (true), (2 > 4) or (1 == 3) (false) | -| not A | not true | not (1 == 2) (true), not (1 == 1) (false) | - -Please note that this doesn't contain every possible operator. - -It is also possible to combine operators. For example: - -```lua -if not A and B then - print("Yay!") -end -``` - -This prints "Yay!" if A is false and B is true. - -Logical and arithmetic operators work the same way; they both accept inputs and -return a value which can be stored. For example: - -```lua -local A = 5 -local is_equal = (A == 5) -if is_equal then - print("Is equal!") -end -``` - -## Programming - -Programming is the action of taking a problem, such as sorting a list -of items, and turning it into steps that a computer can understand. - -Teaching you the logical process of programming is beyond the scope of this book; -however, the following websites are quite useful in developing this: - -* [Codecademy](http://www.codecademy.com/) is one of the best resources for - learning to write code. It provides an interactive tutorial experience. -* [Scratch](https://scratch.mit.edu) is a good resource for starting from - absolute basics, and learning the problem-solving techniques required to program.\\ - Scratch is *designed to teach children* how to program and isn't a serious - programming language. ## Local and Global Scope Whether a variable is local or global determines where it can be written to or -read from. A local variable is only accessible from where it is defined. Here -are some examples: +read from. Global variables can be accessed from anywhere in the script file, +and from any other mod: + +```lua +function one() + foo = "bar" +end + +function two() + print(dump(foo)) -- Output: "bar" +end + +one() +two() +``` + +In constrast, a local variable is only accessible from where it is defined. +Lua defaults to variables being global, so you need to explicitly use the +`local` keyword: ```lua -- Accessible from within this script file @@ -220,21 +118,8 @@ function myfunc() end ``` -In contrast, global variables can be accessed from anywhere in the script file, and -from any other mod. -```lua -function one() - foo = "bar" -end - -function two() - print(dump(foo)) -- Output: "bar" -end - -one() -two() -``` +### Locals should be used as much as possible Local variables should be used whenever possible. Mods should only create one global at most, with the same name as the mod. Creating other globals is sloppy @@ -284,6 +169,9 @@ end mymod.foo("foobar") ``` +`function mymod.foo()` is equivalent to `mymod.foo = function()`, it's just a +nicer way to write it. + ## Including other Lua Scripts The recommended way to include other Lua scripts in a mod is to use *dofile*. @@ -296,11 +184,13 @@ A script can return a value, which is useful for sharing private locals: ```lua -- script.lua -return "Hello world!" +local module = {} +module.message = "Hello World!" +return module -- init.lua local ret = dofile(minetest.get_modpath("modname") .. "/script.lua") -print(ret) -- Hello world! +print(ret.message) -- Hello world! ``` [Later chapters](../quality/clean_arch.html) will discuss how best to split up diff --git a/_en/items/callbacks.md b/_en/items/callbacks.md new file mode 100644 index 0000000..2c03bce --- /dev/null +++ b/_en/items/callbacks.md @@ -0,0 +1,206 @@ +--- +title: Node and Item Callbacks +layout: default +root: ../.. +idx: 2.15 +description: Learn about callbacks, actions, and events, including on_use, on_punch, on_place, on_rightclick +--- + +## Introduction + +Minetest heavily uses a callback-based modding design. A callback is a function +that you give to an API and is called when an event happens. For example, you +can provide an `on_punch` function in a node definition to be called when a player +punches a node. There are also global callbacks like +`minetest.register_on_punchnode` to receive events for all nodes. + +- [Item Callbacks](#item-callbacks) + - [on_use](#on_use) + - [on_place and on_secondary_use](#on_place-and-on_secondary_use) + - [on_drop](#on_drop) + - [after_use](#after_use) +- [item_place vs place_item](#item_place-vs-place_item) +- [Node Callbacks](#node-callbacks) + - [Right-clicking and placing a node](#right-clicking-and-placing-a-node) + - [Punching and digging](#punching-and-digging) + - [...and more!](#and-more) + + +## Item Callbacks + +When a player has a node, craftitem, or tool in their inventory, they may trigger +certain events: + +| Callback | Default binding | Default value | +|------------------|---------------------------|----------------------------------------------| +| on_use | left-click | nil | +| on_place | right-click on a node | `minetest.item_place` | +| on_secondary_use | right-click not on a node | `minetest.item_secondary_use` (does nothing) | +| on_drop | Q | `minetest.item_drop` | +| after_use | digging a node | nil | + + +### on_use + +Having a use callback prevents the item from being used to dig nodes. One common +use of the use callback is for food: + +```lua +minetest.register_craftitem("mymod:mudpie", { + description = "Alien Mud Pie", + inventory_image = "myfood_mudpie.png", + on_use = minetest.item_eat(20), +}) +``` + +The number supplied to the minetest.item_eat function is the number of hit +points healed when this food is consumed. Each heart icon the player has is +worth two hitpoints. A player can usually have up to 10 hearts, which is equal +to 20 hitpoints. + +minetest.item_eat() is a function that returns a function, setting it as the +on_use callback. This means the code above is equivalent to this: + +```lua +minetest.register_craftitem("mymod:mudpie", { + description = "Alien Mud Pie", + inventory_image = "myfood_mudpie.png", + on_use = function(...) + return minetest.do_item_eat(20, nil, ...) + end, +}) +``` + +By understanding how item_eat works by simply returning a function, it's +possible to modify it to do more complex behaviour like playing a custom sound. + + +### on_place and on_secondary_use + +The difference between `on_place` and `on_secondary_use` is that `on_place` is +called when the player is pointing at a node and `on_secondary_use` when the +player isn't. + +Both callbacks are called for all types of items. `on_place` defaults to the +`minetest.item_place` function, which handles calling the `on_rightclick` +callback of the pointed node or placing the wielded item if it is a node. + + +### on_drop + +on_drop is called when the player requests to drop an item, for example using +the drop key (Q) or dragging it outside of the inventory. It defaults to the +`minetest.item_drop` function, which will handle dropping the item. + + +### after_use + +`after_use` is called when digging a node and allows you to customise how wear +is applied to a tool. If after_use doesn't exist, then it is the same as: + +```lua +after_use = function(itemstack, user, node, digparams) + itemstack:add_wear(digparams.wear) + return itemstack +end +``` + + +## item_place vs place_item + +Minetest's API includes many different built-in callback implementations for you +to use. These callbacks are named with the item type first, for example, +`minetest.item_place` and `minetest.node_dig`. Some callback implementations are +used directly whereas some are functions that return the callback: + +```lua +minetest.register_item("mymod:example", { + on_place = minetest.item_place, + on_use = minetest.item_eat(10), +}) +``` + +Minetest's API also includes built-in functions that _do_ something. These are +often named in a confusingly similar way to built-in callback implementations +but have the verb first. Examples include `minetest.place_item` and +`minetest.dig_node` - these functions allow you to dig and place nodes with a +similar effect to players. + + +## Node Callbacks + +When a node is in an inventory, it uses Item Callbacks, as discussed above. When +a node is placed in the world, it uses Node Callbacks. There are quite a lot of +node callbacks, too many to discuss in this book. However, quite a few of them +will be talked about later in the book. + +Several of the callbacks are related to node operations such as placing and +removing from the world. It's important to note that node operation callbacks +like these aren't called from bulk changes - those that set a large number of +nodes at once - for performance reasons. Therefore, you can't rely on these +callbacks to always be called. + + +### Right-clicking and placing a node + +When the user right-clicks with an item whilst pointing at a node, the item's +`on_place` callback is called. By default, this is set to `minetest.item_place`. +If the pointed node has an `on_rightclick` callback and sneak (shift) is held, +then the `on_rightclick` callback is called. Otherwise, `minetest.item_place` +will place the node. + +Placing a node will call both `on_construct` and `after_place_node`. +`on_construct` is called by any node set event that wasn't in bulk and is just +given the node's position and value .`after_place_node` is only called by node +place, and so has more information - such as the placer and itemstack. + +It's important to note that players aren't the only objects that can place +nodes; it's common for mobs and mods to place nodes. To account for this, +`placer` could be a player, entity, or nil. + +```lua +minetest.register_node("mymod:mynode", { + on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + if clicker:is_player() then + minetest.chat_send_player(clicker:get_player_name(), "Hello world!") + end + end, + on_construct = function(pos, node) + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "My node!") + end, + after_place_node = function(pos, placer, itemstack, pointed_thing) + -- Make sure to check placer + if placer and placer:is_player() then + local meta = minetest.get_meta(pos) + meta:set_string("owner", placer:get_player_name()) + end + end, +}) +``` + +### Punching and digging + +Punching is when the player left-clicks for a short period. If the wielded item +has an `on_use` callback, this will be called. Otherwise, the `on_punch` +callback on the pointed node will be called. + +When the player attempts to dig a node, the `on_dig` callback on the node will be called. +This defaults to `minetest.node_dig`, which will check for area protection, wear +out the tool, remove the node, and run the `after_dig_node` callback. + + +```lua +minetest.register_node("mymod:mynode", { + on_punch = function(pos, node, puncher, pointed_thing) + if puncher:is_player() then + minetest.chat_send_player(puncher:get_player_name(), "Ow!") + end + end, +}) +``` + +### ...and more! + +Check out Minetest's Lua API reference for a list of all node callbacks, and +more information on the callbacks above. diff --git a/_en/items/creating_textures.md b/_en/items/creating_textures.md index dd5cc95..190a89b 100644 --- a/_en/items/creating_textures.md +++ b/_en/items/creating_textures.md @@ -25,8 +25,10 @@ available, which cover pixel art in much more detail. - [Using the Pencil](#using-the-pencil) - [Tiling](#tiling) - [Transparency](#transparency) + - [Color Palettes](#color-palettes) - [Editors](#editors) - [MS Paint](#ms-paint) + - [Aseprite / LibreSprite](#aseprite--libresprite) - [GIMP](#gimp) ## Techniques @@ -59,6 +61,13 @@ and some nodes, such as glass. Not all editors support transparency, so make sure you choose an editor which is suitable for the textures you wish to create. +### Color Palettes + +Using a consistent color palette is an easy way to make your art look a lot +better. It's a good idea to use one with a limited number of colors, perhaps 32 +at most. Premade palettes can be found at +[lospec.com](https://lospec.com/palette-list). + ## Editors ### MS Paint @@ -69,16 +78,21 @@ This usually won't matter when making textures for the sides of nodes, but if you need transparency in your textures you should choose a different editor. +### Aseprite / LibreSprite + +[Aseprite](https://www.aseprite.org/) is a proprietary pixel art editor. +It contains a lot of useful features by default such as color palettes and +animation tools. + +[LibreSprite](https://libresprite.github.io/) is an open-source fork of Aseprite +from before it went proprietary. + ### GIMP GIMP is commonly used in the Minetest community. It has quite a high learning curve because many of its features are not immediately obvious. -When using GIMP, the pencil tool can be selected from the Toolbox: - - - -It's also advisable to select the Hard edge checkbox for the eraser tool. +When using GIMP, make sure to use the Pencil tool with the Pixel brush and a +size of 1. It's also advisable to select the "Hard edge" checkbox for the Eraser +tool. diff --git a/_en/items/inventories.md b/_en/items/inventories.md index 198c58e..d903e57 100644 --- a/_en/items/inventories.md +++ b/_en/items/inventories.md @@ -19,6 +19,9 @@ that be a player inventory, a node inventory, or a detached inventory. - [What are ItemStacks and Inventories?](#what-are-itemstacks-and-inventories) - [ItemStacks](#itemstacks) - [Inventory Locations](#inventory-locations) + - [Node Inventories](#node-inventories) + - [Player Inventories](#player-inventories) + - [Detached Inventories](#detached-inventories) - [Lists](#lists) - [Size and Width](#size-and-width) - [Checking Contents](#checking-contents) @@ -33,21 +36,21 @@ that be a player inventory, a node inventory, or a detached inventory. An ItemStack is the data behind a single cell in an inventory. -An *inventory* is a collection of *inventory lists*, each of which -is a 2D grid of ItemStacks. -Inventory lists are simply called *lists* in the context -of inventories. -The point of an inventory is to allow multiple grids when Players -and Nodes only have at most one inventory in them. +An *inventory* is a collection of *inventory lists*, each of which is a 2D grid +of ItemStacks. Inventory lists are referred to as *lists* in the context of +inventories. + +Players and nodes only have a single inventory; lists enable you to have +multiple grids within that inventory. By default, the player has the "main" list +for the bulk of its inventory and a few lists for the crafting system. ## ItemStacks -ItemStacks have four components to them: name, count, wear and metadata. +ItemStacks have four components to them: `name`, `count`, `wear`, and metadata. The item name may be the item name of a registered item, an alias, or an unknown -item name. -Unknown items are common when users uninstall mods, or when mods remove items without -precautions, such as registering aliases. +item name. Unknown items are common when users uninstall mods, or when mods +remove items without precautions, such as registering aliases. ```lua print(stack:get_name()) @@ -58,19 +61,14 @@ if not stack:is_known() then end ``` -The count will always be 0 or greater. -Through normal gameplay, the count should be no more than the maximum stack size -of the item - `stack_max`. -However, admin commands and buggy mods may result in stacks exceeding the maximum -size. +The count will always be 0 or greater. Through normal gameplay, the count should +be no more than the maximum stack size of the item - `stack_max`. However, admin +commands and buggy mods may result in stacks exceeding the maximum size. ```lua print(stack:get_stack_max()) ``` - - - An ItemStack can be empty, in which case the count will be 0. ```lua @@ -78,7 +76,7 @@ print(stack:get_count()) stack:set_count(10) ``` -ItemStacks can be constructed in multiple ways using the ItemStack function. +ItemStacks can be constructed in multiple ways using the ItemStack function: ```lua ItemStack() -- name="", count=0 @@ -87,24 +85,30 @@ ItemStack("default:stone 30") ItemStack({ name = "default:wood", count = 10 }) ``` -Item metadata is an unlimited key-value store for data about the item. -Key-value means that you use a name (called the key) to access the data (called the value). -Some keys have special meaning, such as `description` which is used to have a per-stack -item description. -This will be covered in more detail in the Metadata and Storage chapter. +Item metadata is an unlimited key-value store for data about the item. Key-value +means that you use a name (called the key) to access the data (called the +value). Some keys have special meaning, such as `description` which is used to +have a per-stack item description. This will be covered in more detail in the +[Storage and Metadata](../map/storage.html) chapter. ## Inventory Locations -An Inventory Location is where and how the inventory is stored. -There are three types of inventory location: player, node, and detached. -An inventory is directly tied to one and only one location - updating the inventory -will cause it to update immediately. +An Inventory Location is where and how the inventory is stored. There are three +types of inventory location: player, node, and detached. An inventory is +directly tied to one and only one location - updating the inventory will cause +it to update immediately. -Node inventories are related to the position of a specific node, such as a chest. -The node must be loaded because it is stored in [node metadata](../map/storage.html#metadata). +### Node Inventories + +Node inventories are related to the position of a specific node, such as a +chest. The node must be loaded because it is stored in +[node metadata](../map/storage.html#metadata). ```lua -local inv = minetest.get_inventory({ type="node", pos={x=1, y=2, z=3} }) +on_punch = function(pos, node) + local inv = minetest.get_inventory({ type="node", pos=pos }) + -- now use the inventory +end, ``` The above obtains an *inventory reference*, commonly referred to as *InvRef*. @@ -118,6 +122,8 @@ The location of an inventory reference can be found like so: local location = inv:get_location() ``` +### Player Inventories + Player inventories can be obtained similarly or using a player reference. The player must be online to access their inventory. @@ -127,8 +133,10 @@ local inv = minetest.get_inventory({ type="player", name="player1" }) local inv = player:get_inventory() ``` -A detached inventory is one which is independent of players or nodes. -Detached inventories also don't save over a restart. +### Detached Inventories + +A detached inventory is one that is independent of players or nodes. Detached +inventories also don't save over a restart. ```lua local inv = minetest.get_inventory({ @@ -142,10 +150,9 @@ before accessing it: minetest.create_detached_inventory("inventory_name") ``` -The create_detached_inventory function accepts 3 arguments, where only the first - the inventory name - -is required. -The second argument takes a table of callbacks, which can be used to control how -players interact with the inventory: +The `create_detached_inventory` function accepts 3 arguments, where only the +first - the inventory name - is required. The second argument takes a table of +callbacks, which can be used to control how players interact with the inventory: ```lua -- Input only detached inventory @@ -177,9 +184,10 @@ On the contrary, action callbacks - starting with `on_` - don't have a return va ## Lists -Inventory Lists are a concept used to allow multiple grids to be stored inside a single location. -This is especially useful for the player as there are a number of common lists -which all games have, such as the *main* inventory and *craft* slots. +Inventory Lists are a concept used to allow multiple grids to be stored inside a +single location. This is especially useful for the player as there are several +common lists that all games have, such as the *main* inventory and *craft* +slots. ### Size and Width diff --git a/_en/items/nodes_items_crafting.md b/_en/items/nodes_items_crafting.md index 1955783..452fc53 100644 --- a/_en/items/nodes_items_crafting.md +++ b/_en/items/nodes_items_crafting.md @@ -18,8 +18,6 @@ basic requirements for many mods. - [Item Aliases](#item-aliases) - [Textures](#textures) - [Registering a basic node](#registering-a-basic-node) -- [Actions and Callbacks](#actions-and-callbacks) - - [on_use](#onuse) - [Crafting](#crafting) - [Shaped](#shaped) - [Shapeless](#shapeless) @@ -29,25 +27,24 @@ basic requirements for many mods. ## What are Nodes and Items? -Nodes, craftitems, and tools are all Items. -An item is something that could be found in an inventory - -even though it may not be possible through normal gameplay. +Nodes, craftitems, and tools are all Items. An item is something that could be +found in an inventory - even if it isn't possible through normal gameplay. -A node is an item which can be placed or be found in the world. -Every position in the world must be occupied with one and only one node - -seemingly blank positions are usually air nodes. +A node is an item that can be placed or be found in the world. Every position +in the world must be occupied with one and only one node - seemingly blank +positions are usually air nodes. A craftitem can't be placed and is only found in inventories or as a dropped item in the world. -A tool has the ability to wear and typically has non-default digging capabilities. -In the future, it's likely that craftitems and tools will merge into one type of -item, as the distinction between them is rather artificial. +A tool has the ability to wear and typically has non-default digging +capabilities. In the future, it's likely that craftitems and tools will merge +into one type of item, as the distinction between them is rather artificial. ## Registering Items Item definitions consist of an *item name* and a *definition table*. -The definition table contains attributes which affect the behaviour of the item. +The definition table contains attributes that affect the behaviour of the item. ```lua minetest.register_craftitem("modname:itemname", { @@ -63,25 +60,26 @@ following format: modname:itemname -The modname is the name of the mod in which the item is registered, and the -item name is the name of the item itself. -The item name should be relevant to what the item is and can't already be registered. +The modname is the name of the mod in which the item is registered, and the item +name is the name of the item itself. The item name should be relevant to what +the item is and can't already be registered. + +Both `modname` and `itemname` should only contain lowercase letters, numbers, +and underscores. ### Item Aliases -Items can also have *aliases* pointing to their name. -An *alias* is a pseudo-item name which results in the engine treating any -occurrences of the alias as if it were the item name. -There are two main common uses of this: +Items can also have *aliases* pointing to their name. An *alias* is a +pseudo-item name that results in the engine treating any occurrences of the +alias as if it were the item name. There are two main common uses of this: * Renaming removed items to something else. There may be unknown nodes in the world and in inventories if an item is removed from a mod without any corrective code. * Adding a shortcut. `/giveme dirt` is easier than `/giveme default:dirt`. -Registering an alias is pretty simple. -A good way to remember the order of the arguments is `from → to` where -*from* is the alias and *to* is the target. +Registering an alias is pretty simple. A good way to remember the order of the +arguments is `from → to` where *from* is the alias and *to* is the target. ```lua minetest.register_alias("dirt", "default:dirt") @@ -103,14 +101,16 @@ JPEG textures are supported, but they do not support transparency and are genera bad quality at low resolutions. It is often better to use the PNG format. -Textures in Minetest are usually 16 by 16 pixels. -They can be any resolution, but it is recommended that they are in the order of 2, -for example, 16, 32, 64, or 128. -This is because other resolutions may not be supported correctly on older devices, -resulting in decreased performance. +Textures in Minetest are usually 16 by 16 pixels. They can be any resolution, +but it is recommended that they are in the order of 2, for example, 16, 32, 64, +or 128. This is because other resolutions may not be supported correctly on +older devices, especially phones, resulting in degraded performance. ## Registering a basic node +Registering nodes is similar to registering items, just with a different +function: + ```lua minetest.register_node("mymod:diamond", { description = "Alien Diamond", @@ -120,6 +120,9 @@ minetest.register_node("mymod:diamond", { }) ``` +Node definitions can contain any property in an item definition, and also +contain additional properties specific to nodes. + The `tiles` property is a table of texture names the node will use. When there is only one texture, this texture is used on every side. To give a different texture per-side, supply the names of 6 textures in this order: @@ -128,7 +131,7 @@ To give a different texture per-side, supply the names of 6 textures in this ord (+Y, -Y, +X, -X, +Z, -Z) Remember that +Y is upwards in Minetest, as is the convention with -3D computer graphics. +most 3D computer games. ```lua minetest.register_node("mymod:diamond", { @@ -152,49 +155,6 @@ The `is_ground_content` attribute allows caves to be generated over the stone. This is essential for any node which may be placed during map generation underground. Caves are cut out of the world after all the other nodes in an area have generated. -## Actions and Callbacks - -Minetest heavily uses a callback-based modding design. -Callbacks can be placed in the item definition table to allow response to various -different user events. - -### on_use - -By default, the use callback is triggered when a player left-clicks with an item. -Having a use callback prevents the item being used to dig nodes. -One common use of the use callback is for food: - -```lua -minetest.register_craftitem("mymod:mudpie", { - description = "Alien Mud Pie", - inventory_image = "myfood_mudpie.png", - on_use = minetest.item_eat(20), -}) -``` - -The number supplied to the minetest.item_eat function is the number of hit points -healed when this food is consumed. -Each heart icon the player has is worth two hitpoints. -A player can usually have up to 10 hearts, which is equal to 20 hitpoints. -Hitpoints don't have to be integers (whole numbers); they can be decimals. - -minetest.item_eat() is a function which returns a function, setting it -as the on_use callback. -This means the code above is roughly similar to this: - -```lua -minetest.register_craftitem("mymod:mudpie", { - description = "Alien Mud Pie", - inventory_image = "myfood_mudpie.png", - on_use = function(...) - return minetest.do_item_eat(20, nil, ...) - end, -}) -``` - -By understanding how item_eat works by simply returning a function, it's -possible to modify it to do more complex behaviour such as play a custom sound. - ## Crafting There are several types of crafting recipe available, indicated by the `type` @@ -327,6 +287,7 @@ minetest.register_craft({ }) ``` + ## Tools, Capabilities, and Dig Types Dig types are groups which are used to define how strong a node is when dug diff --git a/_en/map/environment.md b/_en/map/environment.md index fe7cf6d..cd26fc2 100644 --- a/_en/map/environment.md +++ b/_en/map/environment.md @@ -202,7 +202,7 @@ local function emerge_callback(pos, action, -- Send progress message if context.total_blocks == context.loaded_blocks then minetest.chat_send_all("Finished loading blocks!") - end + else local perc = 100 * context.loaded_blocks / context.total_blocks local msg = string.format("Loading blocks %d/%d (%.2f%%)", context.loaded_blocks, context.total_blocks, perc) diff --git a/_en/map/timers.md b/_en/map/timers.md index c0b3143..3f2e1f4 100644 --- a/_en/map/timers.md +++ b/_en/map/timers.md @@ -80,7 +80,7 @@ minetest.register_abm({ nodenames = {"default:dirt_with_grass"}, neighbors = {"default:water_source", "default:water_flowing"}, interval = 10.0, -- Run every 10 seconds - chance = 50, -- Select every 1 in 50 nodes + chance = 50, -- One node has a chance of 1 in 50 to get selected action = function(pos, node, active_object_count, active_object_count_wider) local pos = {x = pos.x, y = pos.y + 1, z = pos.z} diff --git a/_en/players/chat.md b/_en/players/chat.md index 2f2f9e6..21f8175 100644 --- a/_en/players/chat.md +++ b/_en/players/chat.md @@ -8,19 +8,21 @@ redirect_from: /en/chapters/chat.html cmd_online: level: warning title: Offline players can run commands - message:
A player name is passed instead of a player object because mods - can run commands on behalf of offline players. For example, the IRC - bridge allows players to run commands without joining the game.
+ message: | + A player name is passed instead of a player object because mods + can run commands on behalf of offline players. For example, the IRC + bridge allows players to run commands without joining the game. -So make sure that you don't assume that the player is online. - You can check by seeing if
minetest.get_player_by_namereturns a player. + So make sure that you don't assume that the player is online. + You can check by seeing if `minetest.get_player_by_name` returns a player. cb_cmdsprivs: level: warning title: Privileges and Chat Commands - message: The shout privilege isn't needed for a player to trigger this callback. - This is because chat commands are implemented in Lua, and are just - chat messages that begin with a /. + message: | + The shout privilege isn't needed for a player to trigger this callback. + This is because chat commands are implemented in Lua, and are just + chat messages that begin with a /. --- @@ -29,15 +31,20 @@ cb_cmdsprivs: Mods can interact with player chat, including sending messages, intercepting messages, and registering chat commands. -- [Sending Messages to All Players](#sending-messages-to-all-players) -- [Sending Messages to Specific Players](#sending-messages-to-specific-players) +- [Sending Messages](#sending-messages) + - [To All Players](#to-all-players) + - [To Specific Players](#to-specific-players) - [Chat Commands](#chat-commands) -- [Complex Subcommands](#complex-subcommands) + - [Accepting Multiple Arguments](#accepting-multiple-arguments) + - [Using string.split](#using-stringsplit) + - [Using Lua patterns](#using-lua-patterns) - [Intercepting Messages](#intercepting-messages) -## Sending Messages to All Players +## Sending Messages -To send a message to every player in the game, call the chat_send_all function. +### To All Players + +To send a message to every player in the game, call the `chat_send_all` function. ```lua minetest.chat_send_all("This is a chat message to all players") @@ -51,9 +58,9 @@ Here is an example of how this appears in-game: The message appears on a separate line to distinguish it from in-game player chat. -## Sending Messages to Specific Players +### To Specific Players -To send a message to a specific player, call the chat_send_player function: +To send a message to a specific player, call the `chat_send_player` function: ```lua minetest.chat_send_player("player1", "This is a chat message for player1") @@ -80,26 +87,57 @@ minetest.register_chatcommand("foo", { In the above snippet, `interact` is listed as a required [privilege](privileges.html) meaning that only players with the `interact` privilege can run the command. +`param` is a string containing everything a player writes after the chatcommand +name. For example, if a user types `/grantme one,two,three` then `param` will be +`one,two,three`. + Chat commands can return up to two values, the first being a Boolean indicating success, and the second being a message to send to the user. {% include notice.html notice=page.cmd_online %} -## Complex Subcommands +### Accepting Multiple Arguments -It is often required to make complex chat commands, such as: + -* `/msg
- There is also a library written by the author of this book which can be used - to make complex chat commands without patterns called - Chat Command Builder. -
- - ## Intercepting Messages To intercept a message, use register_on_chat_message: diff --git a/_en/players/formspecs.md b/_en/players/formspecs.md index a3061d8..c581a23 100644 --- a/_en/players/formspecs.md +++ b/_en/players/formspecs.md @@ -35,16 +35,16 @@ unexpected windows tend to disrupt gameplay. - [Real or Legacy Coordinates](#real-or-legacy-coordinates) - [Anatomy of a Formspec](#anatomy-of-a-formspec) - - [Elements](#elements) - - [Header](#header) + - [Elements](#elements) + - [Header](#header) - [Guessing Game](#guessing-game) - - [Padding and Spacing](#padding-and-spacing) - - [Receiving Formspec Submissions](#receiving-formspec-submissions) - - [Contexts](#contexts) + - [Padding and Spacing](#padding-and-spacing) + - [Receiving Formspec Submissions](#receiving-formspec-submissions) + - [Contexts](#contexts) - [Formspec Sources](#formspec-sources) - - [Node Meta Formspecs](#node-meta-formspecs) - - [Player Inventory Formspecs](#player-inventory-formspecs) - - [Your Turn](#your-turn) + - [Node Meta Formspecs](#node-meta-formspecs) + - [Player Inventory Formspecs](#player-inventory-formspecs) + - [Your Turn](#your-turn) ## Real or Legacy Coordinates @@ -100,7 +100,7 @@ settings of the client. Here's a formspec which is `2,2` in size: Notice how we explicitly defined the formspec language version. Without this, the legacy system will instead be used instead - which will -prevent the use of consistent element positioning and other new feautures. +prevent the use of consistent element positioning and other new features. The position and anchor elements are used to place the formspec on the screen. The position sets where on the screen the formspec will be, and defaults to @@ -225,9 +225,9 @@ may need to work on multiple forms, or on all forms. The `fields` parameter to the function is a table of the values submitted by the user, indexed by strings. Named elements will appear in the field under their own -name, but only if they are relevent for the event that caused the submission. -For example, a button element will only appear in fields if that particular button -was pressed. +name, depending on the event. Some elements will only be submitted if they caused +the event, such as buttons, and some elements will always appear in submissions, +such as fields. {% include notice.html notice=page.submit_vuln %} @@ -365,9 +365,9 @@ The player inventory formspec is the one shown when the player presses i. The global callback is used to receive events from this formspec, and the formname is `""`. -There are a number of different mods which allow multiple mods to customise -the player inventory. The officially recommended mod is -[Simple Fast Inventory (sfinv)](sfinv.html), and is included in Minetest Game. +There are a number of different mods which allow multiple mods to customise the +player inventory. Minetest Game uses +[SFINV](https://github.com/rubenwardy/sfinv/blob/master/Tutorial.md). ### Your Turn diff --git a/_en/players/sfinv.md b/_en/players/sfinv.md index 19c908e..6671103 100644 --- a/_en/players/sfinv.md +++ b/_en/players/sfinv.md @@ -1,242 +1,5 @@ --- -title: "SFINV: Inventory Formspec" -layout: default -root: ../.. -idx: 4.7 +sitemap: false redirect_from: /en/chapters/sfinv.html +redirect_to: "https://github.com/rubenwardy/sfinv/blob/master/Tutorial.md" --- - -## Introduction - -Simple Fast Inventory (SFINV) is a mod found in Minetest Game that is used to -create the player's inventory [formspec](formspecs.html). SFINV comes with -an API that allows you to add and otherwise manage the pages shown. - -Whilst SFINV by default shows pages as tabs, pages are called pages -because it is entirely possible that a mod or game decides to show them in -some other format instead. -For example, multiple pages could be shown in one formspec. - -- [Registering a Page](#registering-a-page) -- [Receiving events](#receiving-events) -- [Conditionally showing to players](#conditionally-showing-to-players) -- [on_enter and on_leave callbacks](#onenter-and-onleave-callbacks) -- [Adding to an existing page](#adding-to-an-existing-page) - -## Registering a Page - -SFINV provides the aptly named `sfinv.register_page` function to create pages. -Simply call the function with the page's name and its definition: - -```lua -sfinv.register_page("mymod:hello", { - title = "Hello!", - get = function(self, player, context) - return sfinv.make_formspec(player, context, - "label[0.1,0.1;Hello world!]", true) - end -}) -``` - -The `make_formspec` function surrounds your formspec with SFINV's formspec code. -The fourth parameter, currently set as `true`, determines whether the -player's inventory is shown. - -Let's make things more exciting; here is the code for the formspec generation -part of a player admin tab. This tab will allow admins to kick or ban players by -selecting them in a list and clicking a button. - -```lua -sfinv.register_page("myadmin:myadmin", { - title = "Tab", - get = function(self, player, context) - local players = {} - context.myadmin_players = players - - -- Using an array to build a formspec is considerably faster - local formspec = { - "textlist[0.1,0.1;7.8,3;playerlist;" - } - - -- Add all players to the text list, and to the players list - local is_first = true - for _ , player in pairs(minetest.get_connected_players()) do - local player_name = player:get_player_name() - players[#players + 1] = player_name - if not is_first then - formspec[#formspec + 1] = "," - end - formspec[#formspec + 1] = - minetest.formspec_escape(player_name) - is_first = false - end - formspec[#formspec + 1] = "]" - - -- Add buttons - formspec[#formspec + 1] = "button[0.1,3.3;2,1;kick;Kick]" - formspec[#formspec + 1] = "button[2.1,3.3;2,1;ban;Kick + Ban]" - - -- Wrap the formspec in sfinv's layout - -- (ie: adds the tabs and background) - return sfinv.make_formspec(player, context, - table.concat(formspec, ""), false) - end, -}) -``` - -There's nothing new about the above code; all the concepts are -covered above and in previous chapters. - - - -## Receiving events - -You can receive formspec events by adding a `on_player_receive_fields` function -to a sfinv definition. - -```lua -on_player_receive_fields = function(self, player, context, fields) - -- TODO: implement this -end, -``` - -`on_player_receive_fields` works the same as -`minetest.register_on_player_receive_fields`, except that `context` is -given instead of `formname`. -Please note that SFINV will consume events relevant to itself, such as -navigation tab events, so you won't receive them in this callback. - -Now let's implement the `on_player_receive_fields` for our admin mod: - -```lua -on_player_receive_fields = function(self, player, context, fields) - -- text list event, check event type and set index if selection changed - if fields.playerlist then - local event = minetest.explode_textlist_event(fields.playerlist) - if event.type == "CHG" then - context.myadmin_selected_idx = event.index - end - - -- Kick button was pressed - elseif fields.kick then - local player_name = - context.myadmin_players[context.myadmin_selected_idx] - if player_name then - minetest.chat_send_player(player:get_player_name(), - "Kicked " .. player_name) - minetest.kick_player(player_name) - end - - -- Ban button was pressed - elseif fields.ban then - local player_name = - context.myadmin_players[context.myadmin_selected_idx] - if player_name then - minetest.chat_send_player(player:get_player_name(), - "Banned " .. player_name) - minetest.ban_player(player_name) - minetest.kick_player(player_name, "Banned") - end - end -end, -``` - -There's a rather large problem with this, however. Anyone can kick or ban players! You -need a way to only show this to players with the kick or ban privileges. -Luckily SFINV allows you to do this! - -## Conditionally showing to players - -You can add an `is_in_nav` function to your page's definition if you'd like to -control when the page is shown: - -```lua -is_in_nav = function(self, player, context) - local privs = minetest.get_player_privs(player:get_player_name()) - return privs.kick or privs.ban -end, -``` - -If you only need to check one priv or want to perform an 'and', you should use -`minetest.check_player_privs()` instead of `get_player_privs`. - -Note that the `is_in_nav` is only called when the player's inventory formspec is -generated. This happens when a player joins the game, switches tabs, or a mod -requests for SFINV to regenerate. - -This means that you need to manually request that SFINV regenerates the inventory -formspec on any events that may change `is_in_nav`'s result. In our case, -we need to do that whenever kick or ban is granted or revoked to a player: - -```lua -local function on_grant_revoke(grantee, granter, priv) - if priv ~= "kick" and priv ~= "ban" then - return - end - - local player = minetest.get_player_by_name(grantee) - if not player then - return - end - - local context = sfinv.get_or_create_context(player) - if context.page ~= "myadmin:myadmin" then - return - end - - sfinv.set_player_inventory_formspec(player, context) -end - -minetest.register_on_priv_grant(on_grant_revoke) -minetest.register_on_priv_revoke(on_grant_revoke) -``` - -## on_enter and on_leave callbacks - -A player *enters* a tab when the tab is selected and *leaves* a -tab when another tab is about to be selected. -It's possible for multiple pages to be selected if a custom theme is -used. - -Note that these events may not be triggered by the player. -The player may not even have the formspec open at that time. -For example, on_enter is called for the home page when a player -joins the game even before they open their inventory. - -It's not possible to cancel a page change, as that would potentially -confuse the player. - -```lua -on_enter = function(self, player, context) - -end, - -on_leave = function(self, player, context) - -end, -``` - -## Adding to an existing page - -To add content to an existing page, you will need to override the page -and modify the returned formspec. - -```lua -local old_func = sfinv.registered_pages["sfinv:crafting"].get -sfinv.override_page("sfinv:crafting", { - get = function(self, player, context, ...) - local ret = old_func(self, player, context, ...) - - if type(ret) == "table" then - ret.formspec = ret.formspec .. "label[0,0;Hello]" - else - -- Backwards compatibility - ret = ret .. "label[0,0;Hello]" - end - - return ret - end -}) -``` diff --git a/_en/quality/common_mistakes.md b/_en/quality/common_mistakes.md index e45ef8d..9c81501 100644 --- a/_en/quality/common_mistakes.md +++ b/_en/quality/common_mistakes.md @@ -24,7 +24,7 @@ The methods of ObjectRefs will always return nil when invalid, since Minetest 5. Any call will essentially be ignored. You should avoid storing ObjectRefs where possible. If you do to store an -ObjectRef, you should make you check it before use, like so: +ObjectRef, you should make sure you check it before use, like so: ```lua -- This only works in Minetest 5.2+ diff --git a/_en/quality/luacheck.md b/_en/quality/luacheck.md index d9b4410..963196f 100644 --- a/_en/quality/luacheck.md +++ b/_en/quality/luacheck.md @@ -20,7 +20,6 @@ editor to provide alerts to any mistakes. - [Configuring LuaCheck](#configuring-luacheck) - [Troubleshooting](#troubleshooting) - [Using with editor](#using-with-editor) -- [Checking Commits with Travis](#checking-commits-with-travis) ## Installing LuaCheck @@ -102,51 +101,7 @@ It is highly recommended that you find and install a plugin for your editor of c to show you errors without running a command. Most editors will likely have a plugin available. -* **Atom** - `linter-luacheck`. * **VSCode** - Ctrl+P, then paste: `ext install dwenegar.vscode-luacheck` * **Sublime** - Install using package-control: [SublimeLinter](https://github.com/SublimeLinter/SublimeLinter), [SublimeLinter-luacheck](https://github.com/SublimeLinter/SublimeLinter-luacheck). - -## Checking Commits with Travis - -If your project is public and is on Github, you can use TravisCI - a free service -to run jobs on commits to check them. This means that every commit you push will -be checked against LuaCheck, and a green tick or red cross will be displayed next to them -depending on whether LuaCheck finds any mistakes. This is especially helpful for -when your project receives a pull request - you'll be able to see the LuaCheck output -without downloading the code. - -First, you should visit [travis-ci.org](https://travis-ci.org/) and sign in with -your Github account. Then find your project's repo in your Travis profile, -and enable Travis by flipping the switch. - -Next, create a file called .travis.yml with the following content: - -```yml -language: generic -sudo: false -addons: - apt: - packages: - - luarocks -before_install: - - luarocks install --local luacheck -script: -- $HOME/.luarocks/bin/luacheck . -notifications: - email: false -``` - -If your project is a game rather than a mod or mod pack, -change the line after `script:` to: - -```yml -- $HOME/.luarocks/bin/luacheck mods/ -``` - -Now commit and push to Github. Go to your project's page on Github, and click -'commits'. You should see an orange disc next to the commit you just made. -After awhile it should change either into a green tick or a red cross depending on the -outcome of LuaCheck. In either case, you can click the icon to see the build logs -and the output of LuaCheck. diff --git a/_en/quality/readmore.md b/_en/quality/readmore.md index 7ce3dc9..c140c08 100644 --- a/_en/quality/readmore.md +++ b/_en/quality/readmore.md @@ -14,7 +14,6 @@ After you've read this book, take a look at the following. * Minetest's Lua API Reference - [HTML version](https://minetest.gitlab.io/minetest/class-reference/#player-only-no-op-for-other-objects) | [Text version](https://github.com/minetest/minetest/blob/master/doc/lua_api.txt). -* Explore the [Developer Wiki](http://dev.minetest.net/Main_Page). * Look at [existing mods](https://forum.minetest.net/viewforum.php?f=11). ### Lua Programming diff --git a/_en/quality/translations.md b/_en/quality/translations.md new file mode 100644 index 0000000..ab183ea --- /dev/null +++ b/_en/quality/translations.md @@ -0,0 +1,198 @@ +--- +title: Translation (i18n / l10n) +layout: default +root: ../.. +idx: 8.05 +marked_text_encoding: + level: info + title: Marked Text Encoding + message: | + You don't need to know the exact format of marked text, but it might help + you understand. + + ``` + "\27(T@mymod)Hello everyone!\27E" + ``` + + * `\27` is the escape character - it's used to tell Minetest to pay attention as + something special is coming up. This is used for both translations and text + colorisation. + * `(T@mymod)` says that the following text is translatable using the `mymod` + textdomain. + * `Hello everyone!` is the translatable text in English, as passed to the + translator function. + * `\27E` is the escape character again and `E`, used to signal that the end has + been reached. +--- + +## Introduction + +Adding support for translation to your mods and games allows more people to +enjoy them. According to Google Play, 64% of Minetest Android users don't have +English as their primary language. Minetest doesn't track stats for user +languages across all platforms, but there's likely to be a high proportion of +non-English speaking users. + +Minetest allows you to translate your mods and games into different languages by +writing your text in English, and using translation files to map into other +languages. Translation is done on each player's client, allowing each player to +see a different language. + + +- [How does client-side translation work?](#how-does-client-side-translation-work) + - [Marked up text](#marked-up-text) + - [Translation files](#translation-files) +- [Format strings](#format-strings) +- [Best practices and Common Falsehoods about Translation](#best-practices-and-common-falsehoods-about-translation) +- [Server-side translations](#server-side-translations) +- [Conclusion](#conclusion) + + +## How does client-side translation work? + +### Marked up text + +The server needs to tell clients how to translate text. This is done by placing +control characters in text, telling Minetest where and how to translate +text. This is referred to as marked up text, and will be discussed more later. + +To mark text as translatable, use a translator function (`S()`), obtained using +`minetest.get_translator(textdomain)`: + +```lua +local S = minetest.get_translator("mymod") + +minetest.register_craftitem("mymod:item", { + description = S("My Item"), +}) +``` + +The first argument of `get_translator` is the `textdomain`, which acts as a +namespace. Rather than having all translations for a language stored in the same +file, translations are separated into textdomains, with a file per textdomain +per language. The textdomain should be the same as the mod name, as it helps +avoid mod conflicts. + +Marked up text can be used in most places where human-readable text is accepted, +including formspecs, item def fields, infotext, and more. When including marked +text in formspecs, you need to escape the text using `minetest.formspec_escape`. + +When the client encounters translatable text, such as that passed to +`description`, it looks it up in the player's language's translation file. If a +translation cannot be found, it falls back to the English translation. + +Translatable marked up text contains the English source text, the textdomain, +and any additional arguments passed to `S()`. It's essentially a text encoding +of the `S` call, containing all the required information. + +Another type of marked up text is that returned by `minetest.colorize`. + +{% include notice.html notice=page.marked_text_encoding %} + + +### Translation files + +Translation files are media files that can be found in the `locale` folder for +each mod. Currently, the only supported format is `.tr`, but support for more +common formats is likely in the future. Translation files must be named +in the following way: `[textdomain].[lang].tr`. + +Files in the `.tr` start with a comment specifying the textdomain, and then +further lines mapping from the English source text to the translation. + +For example, `mymod.fr.tr`: + +``` +# textdomain: mymod +Hello everyone!=Bonjour à tous ! +I like grapefruit=J'aime le pamplemousse +``` + +You should create translation files based on your mod/game's source code, +using a tool like +[update_translations](https://github.com/minetest-tools/update_translations). +This tool will look for `S(` in your Lua code, and automatically create a +template that translators can use to translate into their language. +It also handles updating the translation files when your source changes. + +You should always put literal text (`"`) inside S rather than using a variable, +as it helps tools find translations. + + +## Format strings + +It's common to need to include variable information within a translation +string. It's important that text isn't just concatenated, as that prevents +translators from changing the order of variables within a sentence. Instead, +you should use the translation system's format/arguments system: + +```lua +minetest.register_on_joinplayer(function(player) + minetest.chat_send_all(S("Everyone, say hi to @1!", player:get_player_name())) +end) +``` + +If you want to include a literal `@` in your translation, you'll need to escape +by writing `@@`. + +You should avoid concatenation *within* a sentence, but it's recommended that +you join multiple sentences using concatenation. This helps translators by +keeping strings smaller. + +```lua +S("Hello @1!", player_name) .. " " .. S("You have @1 new messages.", #msgs) +``` + + +## Best practices and Common Falsehoods about Translation + +* Avoid concatenating text and use format arguments instead. This gives + translators full control over changing the order of things. +* Create translation files automatically, using + [update_translations](https://github.com/minetest-tools/update_translations). +* It's common for variables to change the surrounding text, for example, with + gender and pluralisation. This is often hard to deal with, so is + frequently glossed over or worked around with gender neutral phrasings. +* Translations may be much longer or much smaller than the English text. Make + sure to leave plenty of space. +* Other languages may write numbers in a different way, for example, with commas + as decimal points. `1.000,23`, `1'000'000,32` +* Don't assume that other languages use capitalisation in the same way. + + +## Server-side translations + +Sometimes you need to know the translation of text on the server, for example, +to sort or search text. You can use `get_player_information` to get a player's +language and `get_translated_string` to translate marked text. + +```lua +local list = { + S("Hello world!"), + S("Potato") +} + +minetest.register_chatcommand("find", { + func = function(name, param) + local info = minetest.get_player_information(name) + local language = info and info.language or "en" + + for _, line in ipairs(list) do + local trans = minetest.get_translated_string(language, line) + if trans:contains(query) then + return line + end + end + end, +}) +``` + +## Conclusion + +The translation API allows making mods and games more accessible, but care is +needed in order to use it correctly. + +Minetest is continuously improving, and the translation API is likely to be +extended in the future. For example, support for gettext translation files will +allow common translator tools and platforms (like weblate) to be used, and +there's likely to be support for pluralisation and gender added. diff --git a/_en/quality/unit_testing.md b/_en/quality/unit_testing.md index 643380a..830f99e 100644 --- a/_en/quality/unit_testing.md +++ b/_en/quality/unit_testing.md @@ -17,9 +17,8 @@ we discussed how to structure your code avoid this. - [Your First Test](#your-first-test) - [init.lua](#initlua) - [api.lua](#apilua) - - [tests/api_spec.lua](#testsapispeclua) + - [tests/api_spec.lua](#testsapi_speclua) - [Mocking: Using External Functions](#mocking-using-external-functions) -- [Checking Commits with Travis](#checking-commits-with-travis) - [Conclusion](#conclusion) ## Installing Busted @@ -164,28 +163,6 @@ end) ``` -## Checking Commits with Travis - -The Travis script from the [Automatic Error Checking](luacheck.html) -chapter can be modified to also run Busted. - -```yml -language: generic -sudo: false -addons: - apt: - packages: - - luarocks -before_install: - - luarocks install --local luacheck && luarocks install --local busted -script: -- $HOME/.luarocks/bin/luacheck . -- $HOME/.luarocks/bin/busted . -notifications: - email: false -``` - - ## Conclusion Unit tests will greatly increase the quality and reliability of your project if used diff --git a/_it/basics/lua.md b/_it/basics/lua.md index ebe3bd4..475fd78 100644 --- a/_it/basics/lua.md +++ b/_it/basics/lua.md @@ -11,17 +11,32 @@ redirect_from: /it/chapters/lua.html In questo capitolo parleremo della programmazione in Lua, degli strumenti necessari, e tratteremo alcune tecniche che troverai probabilmente utili. -- [Editor di codice](#editor-di-codice) -- [Programmare in Lua](#programmare-in-lua) - - [Flusso del programma](#flusso-del-programma) - - [Tipi di variabili](#tipi-di-variabili) - - [Operatori matematici](#operatori-matematici) - - [Selezione](#selezione) - - [Operatori logici](#operatori-logici) - [Programmare](#programmare) + - [Programmare in Lua](#programmare-in-lua) +- [Editor di codice](#editor-di-codice) - [Portata locale e globale](#portata-locale-e-globale) + - [Precedenza alla portata locale](#precedenza-alla-portata-locale) - [Inclusione di altri script Lua](#inclusione-di-altri-script-lua) + +## Programmare + +Programmare è l'azione di prendere un problema, come ordinare una lista di oggetti, e tramutarlo in dei passaggi che il computer può comprendere. + +Insegnarti i processi logici della programmazione non rientra nell'ambito di questo libro; tuttavia, i seguenti siti sono alquanto utili per approfondire l'argomento: + +* [Codecademy](http://www.codecademy.com/) è una delle migliori risorse per imparare come scrivere codice; offre un'esperienza guidata interattiva. +* [Scratch](https://scratch.mit.edu) è una buona risorsa quando si comincia dalle basi assolute, imparando le tecniche di problem solving necessarie per la programmazione.\\ + Scratch è *ideato per insegnare ai bambini* e non è un linguaggio serio di programmazione. +* [Programming with Mosh](https://www.youtube.com/user/programmingwithmosh) is + a good YouTube series to learn programming. + +### Programmare in Lua + +Neanche insegnarti come programmare in lua rientra nell'ambito di questo libro. +Tuttavia, se mastichi l'inglese puoi rifarti a quest'altro libro, ["Programming in Lua"](https://www.lua.org/pil/contents.html), per un'eccellente infarinatura sull'argomento. Se invece l'inglese non è il tuo forte, troverai comunque svariate guide in italiano in giro per la rete. + + ## Editor di codice Un editor di codice con evidenziamento delle parole chiave è sufficiente per scrivere script in Lua. @@ -56,126 +71,6 @@ Tra gli editor più famosi che ben si prestano a lavorare in Lua, troviamo: (ne esistono ovviamente anche altri) -## Programmare in Lua - -### Flusso del programma - -I programmi sono una serie di comandi che vengono eseguiti uno dopo l'altro. -Chiamiamo questi comandi "istruzioni". -Il flusso del programma è il come queste istruzioni vengono eseguite, e a differenti tipi di flusso corrispondono comportamenti diversi. -Essi possono essere: - -* Sequenziali: eseguono un'istruzione dopo l'altra, senza salti. -* Selettivi: saltano alcune sequenze a seconda delle condizioni. -* Iteranti: continuano a eseguire le stesse istruzioni finché una condizione non è soddisfatta. - -Quindi, come vengono rappresentate le istruzioni in Lua? - -```lua -local a = 2 -- Imposta 'a' a 2 -local b = 2 -- Imposta 'b' a 2 -local risultato = a + b -- Imposta 'risultato' ad a + b, cioè 4 -a = a + 10 -print("La somma è ".. risultato) -``` - -In quest'esempio, `a`, `b`, e `risultato` sono *variabili*. Le variabili locali si dichiarano tramite l'uso della parola chiave `local` (che vedremo tra poco), e assegnando eventualmente loro un valore iniziale. - -Il simbolo `=` significa *assegnazione*, quindi `risultato = a + b` significa impostare "risultato" ad a + b. -Per quanto riguarda i nomi delle variabili, essi possono essere più lunghi di un carattere - al contrario che in matematica - come visto in `risultato`, e vale anche la pena notare che Lua è *case-sensitive* (differenzia maiuscole da minuscole); `A` è una variabile diversa da `a`. - -### Tipi di variabili - -Una variabile può equivalere solo a uno dei seguenti tipi e può cambiare tipo dopo l'assegnazione. -È buona pratica assicurarsi che sia sempre solo o nil o diversa da nil. - -| Tipo | Descrizione | Esempio | -|----------|---------------------------------|----------------| -| Nil | Non inizializzata. La variabile è vuota, non ha valore | `local A`, `D = nil` | -| Numero | Un numero intero o decimale | `local A = 4` | -| Stringa | Una porzione di testo | `local D = "one two three"` | -| Booleano | Vero o falso (true, false) | `local is_true = false`, `local E = (1 == 1)` | -| Tabella | Liste | Spiegate sotto | -| Funzione | Può essere eseguita. Può richiedere input e ritornare un valore | `local result = func(1, 2, 3)` | - -### Operatori matematici - -Tra gli operatori di Lua ci sono: - -| Simbolo | Scopo | Esempio | -|---------|--------------------|---------------------------| -| A + B | Addizione | 2 + 2 = 4 | -| A - B | Sottrazione | 2 - 10 = -8 | -| A * B | Moltiplicazione | 2 * 2 = 4 | -| A / B | Divisione | 100 / 50 = 2 | -| A ^ B | Potenze | 2 ^ 2 = 22 = 4 | -| A .. B | Concatena stringhe | "foo" .. "bar" = "foobar" | - -Si tenga presente che questa non è comunque una lista esaustiva. - -### Selezione - -Il metodo di selezione più basico è il costrutto if. -Si presenta così: - -```lua -local random_number = math.random(1, 100) -- Tra 1 e 100. -if random_number > 50 then - print("Woohoo!") -else - print("No!") -end -``` - -Questo esempio genera un numero casuale tra 1 e 100. -Stampa poi "Woohoo!" se il numero è superiore a 50, altrimenti stampa "No!". - -### Operatori logici - -Tra gli operatori logici di Lua ci sono: - -| Simbolo | Scopo | Esempio | -|---------|--------------------------------------|-------------------------------------------------------------| -| A == B | Uguale a | 1 == 1 (true), 1 == 2 (false) | -| A ~= B | Non uguale a (diverso da) | 1 ~= 1 (false), 1 ~= 2 (true) | -| A > B | Maggiore di | 5 > 2 (true), 1 > 2 (false), 1 > 1 (false) | -| A < B | Minore di | 1 < 3 (true), 3 < 1 (false), 1 < 1 (false) | -| A >= B | Maggiore o uguale a | 5 >= 5 (true), 5 >= 3 (true), 5 >= 6 (false) | -| A <= B | Minore o uguale a | 3 <= 6 (true), 3 <= 3 (true) | -| A and B | E (entrambi devono essere veri) | (2 > 1) and (1 == 1) (true), (2 > 3) and (1 == 1) (false) | -| A or B | O (almeno uno dei due vero) | (2 > 1) or (1 == 2) (true), (2 > 4) or (1 == 3) (false) | -| not A | non vero | not (1 == 2) (true), not (1 == 1) (false) | - -La lista non è esaustiva, e gli operatori possono essere combinati, come da esempio: - -```lua -if not A and B then - print("Yay!") -end -``` - -Che stampa "Yay!" se `A` è falso e `B` vero. - -Gli operatori logici e matematici funzionano esattamente allo stesso modo; entrambi accettano input e ritornano un valore che può essere immagazzinato. Per esempio: - -```lua -local A = 5 -local is_equal = (A == 5) -if is_equal then - print("È equivalente!") -end -``` - -## Programmare - -Programmare è l'azione di prendere un problema, come ordinare una lista di oggetti, e tramutarlo in dei passaggi che il computer può comprendere. - -Insegnarti i processi logici della programmazione non rientra nell'ambito di questo libro; tuttavia, i seguenti siti sono alquanto utili per approfondire l'argomento: - -* [Codecademy](http://www.codecademy.com/) è una delle migliori risorse per imparare come scrivere codice; offre un'esperienza guidata interattiva. -* [Scratch](https://scratch.mit.edu) è una buona risorsa quando si comincia dalle basi assolute, imparando le tecniche di problem solving necessarie per la programmazione.\\ - Scratch è *ideato per insegnare ai bambini* e non è un linguaggio serio di programmazione. - ## Portata locale e globale L'essere locale o globale di una variabile determina da dove è possibile accederci. @@ -211,6 +106,9 @@ one() two() ``` + +### Precedenza alla portata locale + Le variabili locali dovrebbero venire usate il più possibile, con le mod che creano al massimo una globale corrispondente al nome della mod. Crearne di ulteriori è considerato cattiva programmazione, e Minetest ci avviserà di ciò: diff --git a/_it/index.md b/_it/index.md index b0524ca..5074fbd 100644 --- a/_it/index.md +++ b/_it/index.md @@ -8,7 +8,7 @@ idx: 0.1 ---Viene passato il nome del giocatore al posto del giocatore in sé perché le mod possono eseguire comandi in vece di un giocatore offline. - Per esempio, il bridge IRC permette ai giocatori di eseguire comandi senza dover entrare in gioco.
+ message: | + Viene passato il nome del giocatore al posto del giocatore in sé perché le mod possono eseguire comandi in vece di un giocatore offline. + Per esempio, il ponte IRC permette ai giocatori di eseguire comandi senza dover entrare in gioco. -Assicurati quindi di non dar per scontato che un giocatore sia connesso. - Puoi controllare ciò tramite
minetest.get_player_by_name, per vedere se ritorna qualcosa o meno. + Assicurati quindi di non dar per scontato che un giocatore sia connesso. + Puoi controllare ciò tramite `minetest.get_player_by_name`, per vedere se ritorna qualcosa o meno. cb_cmdsprivs: level: warning title: Privilegi e comandi - message: Il privilegio shout non è necessario per far sì che un giocatore attivi questo callback. - Questo perché i comandi sono implementati in Lua, e sono semplicemente dei messaggi in chat che iniziano con /. + message: | + Il privilegio shout non è necessario per far sì che un giocatore attivi questo richiamo. + Questo perché i comandi sono implementati in Lua, e sono semplicemente dei messaggi in chat che iniziano con /. --- @@ -26,13 +28,18 @@ cb_cmdsprivs: Le mod possono interagire con la chat del giocatore, tra l'inviare messaggi, intercettarli e registrare dei comandi. -- [Inviare messaggi a tutti i giocatori](#inviare-messaggi-a-tutti-i-giocatori) -- [Inviare messaggi a giocatori specifici](#inviare-messaggi-a-giocatori-specifici) +- [Inviare messaggi](#inviare-messaggi) + - [A tutti i giocatori](#a-tutti-i-giocatori) + - [A giocatori specifici](#a-giocatori-specifici) - [Comandi](#comandi) -- [Complex Subcommands](#complex-subcommands) -- [Intercettare i messaggi](#interecettare-i-messaggi) + - [Accettare più argomenti](#accettare-più-argomenti) + - [Usare string.split](#usare-stringsplit) + - [Usare i pattern Lua](#usare-i-pattern-lua) +- [Intercettare i messaggi](#intercettare-i-messaggi) -## Inviare messaggi a tutti i giocatori +## Inviare messaggi + +### A tutti i giocatori Per inviare un messaggio a tutti i giocatori connessi in gioco, si usa la funzione `chat_send_all`: @@ -48,7 +55,7 @@ Segue un esempio di come apparirerebbe in gioco: Il messaggio appare su una nuova riga, per distinguerlo dai messaggi dei giocatori. -## Inviare messaggi a giocatori specifici +### A giocatori specifici Per inviare un messaggio a un giocatore in particolare, si usa invece la funzione `chat_send_player`: @@ -75,21 +82,50 @@ minetest.register_chatcommand("foo", { Nel codice qui in alto, `interact` è elencato come [privilegio](privileges.html) necessario; in altre parole, solo i giocatori che hanno quel privilegio possono usare il comando. +`param` è una stringa contenente tutto ciò che un giocatore scrive dopo il nome del comando. +Per esempio, in `/grantme uno,due,tre`, `param` equivarrà a `uno,due,tre`. + I comandi ritornano un massimo di due valori, dove il primo è un booleano che indica l'eventuale successo, mentre il secondo è un messaggio da inviare all'utente. {% include notice.html notice=page.cmd_online %} -## Sottocomandi complessi -È spesso necessario creare dei comandi complessi, come per esempio: +### Accettare più argomenti -* `/msg