Compare commits
5 Commits
c455aff265
...
0c6cfc1563
Author | SHA1 | Date |
---|---|---|
rubenwardy | 0c6cfc1563 | |
rubenwardy | 089ea288dd | |
Travis Wrightsman | f45055554b | |
rubenwardy | 5e0399a7af | |
rubenwardy | f1f051c3cb |
1
Gemfile
1
Gemfile
|
@ -1,6 +1,7 @@
|
|||
source "https://rubygems.org"
|
||||
|
||||
gem "jekyll"
|
||||
gem "webrick"
|
||||
|
||||
group :jekyll_plugins do
|
||||
gem "jekyll-sitemap"
|
||||
|
|
34
Gemfile.lock
34
Gemfile.lock
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
})
|
||||
```
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
})
|
||||
```
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue