Compare commits

...

5 Commits

Author SHA1 Message Date
rubenwardy 0c6cfc1563 Small improvements 2021-05-08 21:13:25 +01:00
rubenwardy 089ea288dd Remove ChatCmdBuilder chapter 2021-05-07 16:17:28 +01:00
Travis Wrightsman f45055554b Fix modpack conf file extension 2021-03-27 17:02:32 +01:00
rubenwardy 5e0399a7af Storage: Fix example
Fixes #106
2021-02-21 04:26:49 +00:00
rubenwardy f1f051c3cb Inventories: 0 is used to prevent take, not -1 2021-02-21 04:23:48 +00:00
14 changed files with 63 additions and 422 deletions

View File

@ -1,6 +1,7 @@
source "https://rubygems.org"
gem "jekyll"
gem "webrick"
group :jekyll_plugins do
gem "jekyll-sitemap"

View File

@ -4,31 +4,31 @@ GEM
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
colorator (1.1.0)
concurrent-ruby (1.1.7)
em-websocket (0.5.1)
concurrent-ruby (1.1.8)
em-websocket (0.5.2)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0.6.0)
eventmachine (1.2.7)
ffi (1.13.1)
ffi (1.15.0)
forwardable-extended (2.6.0)
http_parser.rb (0.6.0)
i18n (1.8.5)
i18n (1.8.10)
concurrent-ruby (~> 1.0)
jekyll (4.1.1)
jekyll (4.2.0)
addressable (~> 2.4)
colorator (~> 1.0)
em-websocket (~> 0.5)
i18n (~> 1.0)
jekyll-sass-converter (~> 2.0)
jekyll-watch (~> 2.0)
kramdown (~> 2.1)
kramdown (~> 2.3)
kramdown-parser-gfm (~> 1.0)
liquid (~> 4.0)
mercenary (~> 0.4.0)
pathutil (~> 0.9)
rouge (~> 3.0)
safe_yaml (~> 1.0)
terminal-table (~> 1.8)
terminal-table (~> 2.0)
jekyll-redirect-from (0.16.0)
jekyll (>= 3.3, < 5.0)
jekyll-sass-converter (2.1.0)
@ -37,37 +37,39 @@ GEM
jekyll (>= 3.7, < 5.0)
jekyll-watch (2.2.1)
listen (~> 3.0)
kramdown (2.3.0)
kramdown (2.3.1)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.3)
listen (3.2.1)
listen (3.5.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.4.0)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (4.0.5)
rb-fsevent (0.10.4)
public_suffix (4.0.6)
rb-fsevent (0.11.0)
rb-inotify (0.10.1)
ffi (~> 1.0)
rexml (3.2.4)
rouge (3.22.0)
rexml (3.2.5)
rouge (3.26.0)
safe_yaml (1.0.5)
sassc (2.4.0)
ffi (~> 1.9)
terminal-table (1.8.0)
terminal-table (2.0.0)
unicode-display_width (~> 1.1, >= 1.1.1)
unicode-display_width (1.7.0)
webrick (1.7.0)
PLATFORMS
ruby
x86_64-linux
DEPENDENCIES
jekyll
jekyll-redirect-from
jekyll-sitemap
webrick
BUNDLED WITH
2.0.2
2.2.16

View File

@ -68,30 +68,15 @@ They are, in order:
particular world.
Eg: `minetest/worlds/world/worldmods/`
Minetest will check the locations in the order given above. If it encounters a mod
with a name the same as one found previously, the later 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.
`minetest` is the user-data directory. You can find the location of the
user-data directory by opening up Minetest and clicking
"Open User Data Directory" in the Credits tab.
The actual location of each mod load path depends on what operating system you're
using, and how you installed Minetest.
When loading mods, Minetest will check each of the above locations in order.
If it encounters a mod with a name the same as one found previously, the later
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.
* **Windows:**
* For portable builds, ie: from a .zip file, just go to the directory where
you extracted the zip and look for the `games`, `mods`, and `worlds`
directories.
* For installed builds, ie: from a setup.exe,
look in C:\\\\Minetest or C:\\\\Games\\Minetest.
* **GNU/Linux:**
* For system-wide installs, look in `~/.minetest`.
Note that `~` means the user home directory, and that files and directories
starting with a dot (`.`) are hidden.
* For portable installs, look in the build directory.
* For Flatpak installs, look in `~/.var/app/net.minetest.Minetest/.minetest/mods/`.
* **MacOS**
* Look in `~/Library/Application Support/minetest/`.
Note that `~` means the user home, ie: `/Users/USERNAME/`.
## Mod Directory
@ -154,7 +139,7 @@ and moved together. They are useful if you want to supply multiple mods to
a player, but don't want to make them download each one individually.
modpack1
├── modpack.lua (required) - signals that this is a mod pack
├── modpack.conf (required) - signals that this is a mod pack
├── mod1
│   └── ... mod files
└── mymod (optional)
@ -184,6 +169,12 @@ minetest.register_node("mymod:node", {
tiles = {"mymod_node.png"},
groups = {cracky = 1}
})
minetest.register_craft({
type = "shapeless",
output = "mymod:node 3",
recipe = { "default:dirt", "default:stone" },
})
```
### mod.conf
@ -191,10 +182,9 @@ minetest.register_node("mymod:node", {
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
which will be explained in the next chapter.\\
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.
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.

View File

@ -142,7 +142,7 @@ before accessing it:
minetest.create_detached_inventory("inventory_name")
```
The create_detached_inventory function accepts 3 arguments, where only the first - the 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:
@ -159,7 +159,7 @@ minetest.create_detached_inventory("inventory_name", {
end,
allow_take = function(inv, listname, index, stack, player)
return -1 -- don't allow taking
return 0 -- don't allow taking
end,
on_put = function(inv, listname, index, stack, player)
@ -171,7 +171,7 @@ minetest.create_detached_inventory("inventory_name", {
```
Permission callbacks - ie: those starting with `allow_` - return the number
of items to transfer, with -1 being used to prevent transfer completely.
of items to transfer, with 0 being used to prevent transfer completely.
On the contrary, action callbacks - starting with `on_` - don't have a return value.

View File

@ -148,7 +148,7 @@ minetest.register_node("mymod:diamond", {
})
```
The is_ground_content attribute allows caves to be generated over the stone.
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.

View File

@ -23,15 +23,17 @@ In this chapter, you will learn how to perform basic actions on the map.
## Map Structure
The Minetest map is split into MapBlocks, each MapBlocks being a cube of size 16.
As players travel around the map, MapBlocks are created, loaded, and unloaded.
Areas of the map which are not yet loaded are full of *ignore* nodes, an impassable
unselectable placeholder node. Empty space is full of *air* nodes, an invisible node
you can walk through.
The Minetest map is split into MapBlocks, each MapBlocks being a cube of
size 16. As players travel around the map, MapBlocks are created, loaded,
activated, and unloaded. Areas of the map which are not yet loaded are full of
*ignore* nodes, an impassable unselectable placeholder node. Empty space is
full of *air* nodes, an invisible node you can walk through.
An active MapBlock is one which is loaded and has updates running on it.
Loaded map blocks are often referred to as *active blocks*. Active Blocks can be
read from or written to by mods or players, and have active entities. The Engine also
performs operations on the map, such as performing liquid physics.
read from or written to by mods or players, and have active entities. The Engine
also performs operations on the map, such as performing liquid physics.
MapBlocks can either be loaded from the world database or generated. MapBlocks
will be generated up to the map generation limit (`mapgen_limit`) which is set

View File

@ -189,7 +189,7 @@ function backend.set_foo(key, value)
storage:set_string(key, minetest.serialize(value))
end
function backend.get_foo(key, value)
function backend.get_foo(key)
return minetest.deserialize(storage:get_string(key))
end

View File

@ -124,9 +124,9 @@ Patterns would probably be the
or the [PIL documentation](https://www.lua.org/pil/20.2.html).
<p class="book_hide">
There is also a library written by the author of this book which can be used
to make complex chat commands without patterns called
<a href="chat_complex.html">Chat Command Builder</a>.
There is also a library written by the author of this book which can be used
to make complex chat commands without patterns called
<a href="https://gitlab.com/rubenwardy/ChatCmdBuilder">Chat Command Builder</a>.
</p>

View File

@ -1,183 +0,0 @@
---
title: Chat Command Builder
layout: default
root: ../..
idx: 4.3
description: Use ChatCmdBuilder to make a complex chat command
redirect_from: /en/chapters/chat_complex.html
---
## Introduction <!-- omit in toc -->
This chapter will show you how to make complex chat commands with ChatCmdBuilder,
such as `/msg <name> <message>`, `/team join <teamname>` or `/team leave <teamname>`.
Note that ChatCmdBuilder is a library created by the author of this book, and most
modders tend to use the method outlined in the
[Chat and Commands](chat.html#complex-subcommands) chapter.
- [Why ChatCmdBuilder?](#why-chatcmdbuilder)
- [Routes](#routes)
- [Subcommand functions](#subcommand-functions)
- [Installing ChatCmdBuilder](#installing-chatcmdbuilder)
- [Admin complex command](#admin-complex-command)
## Why ChatCmdBuilder?
Traditionally mods implemented these complex commands using Lua patterns.
```lua
local name = string.match(param, "^join ([%a%d_-]+)")
```
I, however, find Lua patterns annoying to write and unreadable.
Because of this, I created a library to do this for you.
```lua
ChatCmdBuilder.new("sethp", function(cmd)
cmd:sub(":target :hp:int", function(name, target, hp)
local player = minetest.get_player_by_name(target)
if player then
player:set_hp(hp)
return true, "Killed " .. target
else
return false, "Unable to find " .. target
end
end)
end, {
description = "Set hp of player",
privs = {
kick = true
-- ^ probably better to register a custom priv
}
})
```
`ChatCmdBuilder.new(name, setup_func, def)` creates a new chat command called
`name`. It then calls the function passed to it (`setup_func`), which then creates
subcommands. Each `cmd:sub(route, func)` is a subcommand.
A subcommand is a particular response to an input param. When a player runs
the chat command, the first subcommand that matches their input will be run,
and no others. If no subcommands match, then the user will be told of the invalid
syntax. For example, in the above code snippet if a player
types something of the form `/sethp username 12` then the function passed
to cmd:sub will be called. If they type `/sethp 12 bleh`, then a wrong
input message will appear.
`:name :hp:int` is a route. It describes the format of the param passed to /teleport.
## Routes
A route is made up of terminals and variables. Terminals must always be there.
For example, `join` in `/team join :username :teamname`. The spaces also count
as terminals.
Variables can change value depending on what the user types. For example, `:username`
and `:teamname`.
Variables are defined as `:name:type`. The `name` is used in the help documentation.
The `type` is used to match the input. If the type is not given, then the type is
`word`.
Valid types are:
* `word` - default. Any string without spaces.
* `int` - Any integer/whole number, no decimals.
* `number` - Any number, including ints and decimals.
* `pos` - 1,2,3 or 1.1,2,3.4567 or (1,2,3) or 1.2, 2 ,3.2
* `text` - Any string. There can only ever be one text variable,
no variables or terminals can come afterwards.
In `:name :hp:int`, there are two variables:
* `name` - type of `word` as no type is specified. Accepts any string without spaces.
* `hp` - type of `int`
## Subcommand functions
The first argument is the caller's name. The variables are then passed to the
function in order.
```lua
cmd:sub(":target :hp:int", function(name, target, hp)
-- subcommand function
end)
```
## Installing ChatCmdBuilder
The source code can be found and downloaded on
[Github](https://github.com/rubenwardy/ChatCmdBuilder/).
There are two ways to install:
1. Install ChatCmdBuilder as a mod and depend on it.
2. Include the init.lua file in ChatCmdBuilder as chatcmdbuilder.lua in your mod,
and dofile it.
## Admin complex command
Here is an example that creates a chat command that allows us to do this:
* `/admin kill <username>` - kill user
* `/admin move <username> to <pos>` - teleport user
* `/admin log <username>` - show report log
* `/admin log <username> <message>` - log to report log
```lua
local admin_log
local function load()
admin_log = {}
end
local function save()
-- todo
end
load()
ChatCmdBuilder.new("admin", function(cmd)
cmd:sub("kill :name", function(name, target)
local player = minetest.get_player_by_name(target)
if player then
player:set_hp(0)
return true, "Killed " .. target
else
return false, "Unable to find " .. target
end
end)
cmd:sub("move :name to :pos:pos", function(name, target, pos)
local player = minetest.get_player_by_name(target)
if player then
player:setpos(pos)
return true, "Moved " .. target .. " to " ..
minetest.pos_to_string(pos)
else
return false, "Unable to find " .. target
end
end)
cmd:sub("log :username", function(name, target)
local log = admin_log[target]
if log then
return true, table.concat(log, "\n")
else
return false, "No entries for " .. target
end
end)
cmd:sub("log :username :message", function(name, target, message)
local log = admin_log[target] or {}
table.insert(log, message)
admin_log[target] = log
save()
return true, "Logged"
end)
end, {
description = "Admin tools",
privs = {
kick = true,
ban = true
}
})
```

View File

@ -140,7 +140,7 @@ minetest.create_detached_inventory("inventory_name", {
end,
allow_take = function(inv, listname, index, stack, player)
return -1 -- non permette di rimuoverli
return 0 -- non permette di rimuoverli
end,
on_put = function(inv, listname, index, stack, player)
@ -151,7 +151,7 @@ minetest.create_detached_inventory("inventory_name", {
})
```
I callback dei permessi - quelle che iniziano con `allow_` - ritornano il numero degli oggetti da trasferire, e si usa -1 per impedirne del tutto l'azione.
I callback dei permessi - quelle che iniziano con `allow_` - ritornano il numero degli oggetti da trasferire, e si usa 0 per impedirne del tutto l'azione.
I callback delle azioni - quelle che iniziano con `on_` - non ritornano invece alcun valore.

View File

@ -168,7 +168,7 @@ function backend.set_foo(key, value)
memoria:set_string(key, minetest.serialize(value))
end
function backend.get_foo(key, value)
function backend.get_foo(key)
return minetest.deserialize(memoria:get_string(key))
end

View File

@ -113,7 +113,9 @@ Questo è come molte mod implementano comandi complessi.
Una guida più completa ai pattern è probabilmente quella su [lua-users.org](http://lua-users.org/wiki/PatternsTutorial) o la [documentazione PIL](https://www.lua.org/pil/20.2.html).
<p class="book_hide">
C'è anche una libreria scritta dall'autore di questo libro che può essere usata per creare comandi complessi senza l'utilizzo di pattern: <a href="chat_complex.html">Chat Command Builder</a>.
C'è anche una libreria scritta dall'autore di questo libro che può essere usata
per creare comandi complessi senza l'utilizzo di pattern:
<a href="https://gitlab.com/rubenwardy/ChatCmdBuilder">Chat Command Builder</a>.
</p>

View File

@ -1,173 +0,0 @@
---
title: Chat Command Builder
layout: default
root: ../..
idx: 4.3
description: Creazione di comandi complessi semplificandosi la vita
redirect_from: /it/chapters/chat_complex.html
---
## Introduzione <!-- omit in toc -->
Questo capitolo ti mostrerà come creare comandi complessi con ChatCmdBuilder, come `/msg <nome> <messaggio>`, `/team entra <nometeam>` o `/team esci <nometeam>`.
Tieni conto che ChatCmdBuilder è una libreria creata dall'autore di questo libro, e che molti modder tendono a usare il metodo illustrato nel capitolo [Chat e comandi](chat.html#complex-subcommands).
- [Perché ChatCmdBuilder?](#perche-chatcmdbuilder)
- [Tratte](#tratte)
- [Funzioni nei sottocomandi](#funzioni-nei-sottocomandi)
- [Installare ChatCmdBuilder](#installare-chatcmdbuilder)
- [Esempio: comando complesso /admin](#esempio-comando-complesso-admin)
## Perché ChatCmdBuilder?
Le mod tradizionali implementano questi comandi complessi usando i pattern Lua.
```lua
local nome = string.match(param, "^join ([%a%d_-]+)")
```
Io, tuttavia, trovo i pattern Lua illeggibili e scomodi.
Per via di ciò, ho creato una libreria che ti semplifichi la vita.
```lua
ChatCmdBuilder.new("sethp", function(cmd)
cmd:sub(":target :hp:int", function(name, target, hp)
local giocatore = minetest.get_player_by_name(target)
if giocatore then
giocatore:set_hp(hp)
return true, "Gli hp di " .. target .. " sono ora " .. hp
else
return false, "Giocatore " .. target .. " non trovato"
end
end)
end, {
description = "Imposta gli hp del giocatore",
privs = {
kick = true
-- ^ è probabilmente meglio impostare un nuovo privilegio
}
})
```
`ChatCmdBuilder.new(name, setup_func, def)` crea un nuovo comando chiamato `name`.
Poi, chiama la funzione passatagli (`setup_func`), che crea a sua volta i sottocomandi.
Ogni `cmd:sub(route, func)` è un sottocomando.
Un sottocomando è una particolare risposta a un parametro di input.
Quando un giocatore esegue il comando, il primo sottocomando che combacia con l'input verrà eseguito.
Se non ne viene trovato nessuno, il giocatore verrà avvisato della sintassi non valida.
Nel codice qui in alto, per esempio, se qualcuno scrive qualcosa come `/sethp nickname 12`, la funzione corrispondente verrà chiamata.
Tuttavia, qualcosa come `/sethp 12 bleh` genererà un messaggio d'errore.
`:name :hp:int` è una tratta.
Descrive il formato del parametro passato a /teleport.
## Tratte
Una tratta è composta di fermate e variabili, dove le prime sono obbligatorie.
Una fermata è per esempio `crea` in `/team crea :nometeam :giocatorimassimi:int`, ma anche gli spazi contano come tali.
Le variabili possono cambiare valore a seconda di cosa scrive l'utente. Per esempio `:nometeam` e `:giocatorimassimi:int`.
Le variabili sono definite con `:nome:tipo`: il nome è usato nella documentazione, mentre il tipo è usato per far combaciare l'input.
Se il tipo non è specificato, allora sarà di base `word`.
I tipi consentiti sono:
* `word` - Predefinito. Qualsiasi stringa senza spazi;
* `int` - Qualsiasi numero intero;
* `number` - Qualsiasi numero, decimali inclusi;
* `pos` - Coordinate. Il formato può essere 1,2,3, o 1.1,2,3.4567, o (1,2,3), o ancora 1.2, 2 ,3.2;
* `text` - Qualsiasi stringa, spazi inclusi. Può esserci solo un `text` e non può essere seguito da nient'altro.
In `:nome :hp:int`, ci sono due variabili:
* `name` - di tipo `word` in quanto non è stato specificato
* `hp` - di tipo `int`, quindi un numero intero
## Funzioni nei sottocomandi
Il primo parametro è il nome di chi invia il comando. Le variabili sono poi passate alla funzione nell'ordine in cui sono state dichiarate.
```lua
cmd:sub(":target :hp:int", function(name, target, hp)
-- funzione del sottocomando
end)
```
## Installare ChatCmdBuilder
Il codice sorgente può essere trovato e scaricato su
[Github](https://github.com/rubenwardy/ChatCmdBuilder/).
Ci sono due modi per installarlo:
1. Installarlo come una mod a sé stante;
2. Includere nella tua mod l'init.lua di ChatCmdBuilder rinominandolo chatcmdbuilder.lua, e integrarlo tramite `dofile`.
## Esempio: comando complesso /admin
Segue un esempio che crea un comando che aggiunge le seguenti funzioni per chi ha il permesso `kick` e `ban` (quindi, in teoria, un admin):
* `/admin uccidi <nome>` - uccide un utente;
* `/admin sposta <nome> a <pos>` - teletrasporta un utente;
* `/admin log <nome>` - mostra il log di un utente;
* `/admin log <nome> <messaggio>` - aggiunge un messaggio al log di un utente.
```lua
local admin_log
local function carica()
admin_log = {}
end
local function salva()
-- todo
end
carica()
ChatCmdBuilder.new("admin", function(cmd)
cmd:sub("uccidi :nome", function(name, target)
local giocatore = minetest.get_player_by_name(target)
if giocatore then
giocatore:set_hp(0)
return true, "Hai ucciso " .. target
else
return false, "Unable to find " .. target
end
end)
cmd:sub("sposta :nome to :pos:pos", function(nome, target, pos)
local giocatore = minetest.get_player_by_name(target)
if giocatore then
giocatore:setpos(pos)
return true, "Giocatore " .. target .. " teletrasportato a " ..
minetest.pos_to_string(pos)
else
return false, "Giocatore " .. target .. " non trovato"
end
end)
cmd:sub("log :nome", function(name, target)
local log = admin_log[target]
if log then
return true, table.concat(log, "\n")
else
return false, "Nessuna voce per " .. target
end
end)
cmd:sub("log :nome :messaggio", function(name, target, messaggio)
local log = admin_log[target] or {}
table.insert(log, messaggio)
admin_log[target] = log
salva()
return true, "Aggiunto"
end)
end, {
description = "Strumenti per gli admin",
privs = {
kick = true,
ban = true
}
})
```

View File

@ -118,7 +118,7 @@ h1 {
}
h2 {
border-bottom: 1px solid black;
border-bottom: 1px solid #bbb;
margin: 30px 0 10px 0;
display: block;
padding: 0 0 5px 0;