Remove SFINV chapter

This commit is contained in:
rubenwardy 2022-07-31 20:33:16 +01:00
parent f8c9da8261
commit df46f465cd
5 changed files with 27 additions and 482 deletions

View File

@ -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
@ -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

View File

@ -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 <!-- omit in toc -->
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.
<figure>
<img src="{{ page.root }}//static/sfinv_admin_fs.png" alt="Player Admin Page">
</figure>
## 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
})
```

View File

@ -29,16 +29,16 @@ Tieni presente che se non si ha bisogno di ricevere input dal giocatore, per ese
- [Coordinate reali o datate](#coordinate-reali-o-datate)
- [Anatomia di un formspec](#anatomia-di-un-formspec)
- [Elementi](#elementi)
- [Intestazione](#intestazione)
- [Elementi](#elementi)
- [Intestazione](#intestazione)
- [Esempio: indovina un numero](#esempio-indovina-un-numero)
- [Imbottitura e spaziatura](#imbottitura-e-spaziatura)
- [Ricevere i moduli di compilazione](#ricevere-i-moduli-di-compilazione)
- [Contesti](#contesti)
- [Imbottitura e spaziatura](#imbottitura-e-spaziatura)
- [Ricevere i moduli di compilazione](#ricevere-i-moduli-di-compilazione)
- [Contesti](#contesti)
- [Ricavare un formspec](#ricavare-un-formspec)
- [Formspec nei nodi](#formspec-nei-nodi)
- [Inventario del giocatore](#inventario-del-giocatore)
- [Il tuo turno](#il-tuo-turno)
- [Formspec nei nodi](#formspec-nei-nodi)
- [Inventario del giocatore](#inventario-del-giocatore)
- [Il tuo turno](#il-tuo-turno)
## Coordinate reali o datate
@ -321,7 +321,7 @@ L'inventario del giocatore è un formspec, che viene mostrato al premere "I".
Il callback globale viene usato per ricevere eventi dall'inventario, e il suo nome è `""`.
Ci sono svariate mod che permettono ad altrettante mod di personalizzare l'inventario del giocatore.
La mod ufficialmente raccomandata è [Simple Fast Inventory (sfinv)](sfinv.html), ed è inclusa in Minetest Game.
La mod ufficialmente raccomandata è [SFINV](https://github.com/rubenwardy/sfinv/blob/master/Tutorial.md), ed è inclusa in Minetest Game.
### Il tuo turno

View File

@ -1,223 +1,4 @@
---
title: "SFINV"
layout: default
root: ../..
idx: 4.7
description: una mod per rendere più semplice la creazione di un inventario complesso
redirect_from: /it/chapters/sfinv.html
sitemap: false
redirect_to: "https://github.com/rubenwardy/sfinv/blob/master/Tutorial.md"
---
## Introduzione <!-- omit in toc -->
Simple Fast Inventory (SFINV) è una mod presente in Minetest Game, usata per creare il [formspec](formspecs.html) del giocatore.
SFINV ha un'API che permette di aggiungere e altresì gestire le pagine mostrate.
Mentre SFINV di base mostra le pagine come finestre, le pagine sono chiamate tali in quanto è assolutamente possibile che una mod o un gioco decidano di mostrarle in un altro formato.
Per esempio, più pagine possono essere mostrate nel medesimo formspec.
- [Registrare una pagina](#registrare-una-pagina)
- [Ricevere eventi](#ricevere-eventi)
- [Condizioni per la visualizzazione](#condizioni-per-la-visualizzazione)
- [Callback on_enter e on_leave](#callback-onenter-e-onleave)
- [Aggiungere a una pagina esistente](#aggiungere-a-una-pagina-esistente)
## Registrare una pagina
SFINV fornisce la funzione chiamata `sfinv.register_page` per creare nuove pagine.
Basta chiamare la funzione con il nome che si vuole assegnare alla pagina e la sua definizione:
```lua
sfinv.register_page("miamod:ciao", {
title = "Ciao!",
get = function(self, player, context)
return sfinv.make_formspec(player, context,
"label[0.1,0.1;Ciao mondo!]", true)
end
})
```
La funzione `make_formspec` circonda il formspec con il codice di SFINV.
Il quarto parametro, attualmente impostato a `true`, determina se l'inventario del giocatore è mostrato.
Rendiamo le cose più eccitanti; segue il codice della generazione di un formspec per gli admin.
Questa finestra permetterà agli admin di cacciare o bannare i giocatori selezionandoli da una lista e premendo un pulsante.
```lua
sfinv.register_page("mioadmin:mioadmin", {
title = "Finestra",
get = function(self, player, context)
local giocatori = {}
context.mioadmin_giocatori = giocatori
-- Usare un array per costruire un formspec è decisamente più veloce
local formspec = {
"textlist[0.1,0.1;7.8,3;lista_giocatori;"
}
-- Aggiunge tutti i giocatori sia alla lista testuale che a quella - appunto - dei giocatori
local primo = true
for _ , giocatore in pairs(minetest.get_connected_players()) do
local nome_giocatore = giocatore:get_player_name()
giocatori[#giocatori + 1] = nome_giocatore
if not primo then
formspec[#formspec + 1] = ","
end
formspec[#formspec + 1] =
minetest.formspec_escape(nome_giocatore)
primo = false
end
formspec[#formspec + 1] = "]"
-- Aggiunge i pulsanti
formspec[#formspec + 1] = "button[0.1,3.3;2,1;caccia;Caccia]"
formspec[#formspec + 1] = "button[2.1,3.3;2,1;banna;Caccia e Banna]"
-- Avvolge il formspec nella disposizione di SFINV
-- (es: aggiunge le linguette delle finestre e lo sfondo)
return sfinv.make_formspec(player, context,
table.concat(formspec, ""), false)
end,
})
```
Non c'è niente di nuovo in questa parte di codice; tutti i concetti sono già stati trattati o qui in alto o nei precedenti capitoli.
<figure>
<img src="{{ page.root }}//static/sfinv_admin_fs.png" alt="Pagina per gli amministratori">
</figure>
## Ricevere eventi
Puoi ricevere eventi formspec tramite l'aggiunta della funzione `on_player_receive_fields` nella definizione SFINV.
```lua
on_player_receive_fields = function(self, player, context, fields)
-- TODO: implementarlo
end,
```
`on_player_receive_fields` funziona alla stessa maniera di `minetest.register_on_player_receive_fields`, con la differenza che viene richiesto il contesto al posto del nome del form.
Tieni a mente che gli eventi interni di SFINV, come la navigazione tra le varie finestre, vengono gestiti dentro la mod stessa, e che quindi non verranno ricevuti in questo callback.
Implementiamo ora `on_player_receive_fields` nella mod:
```lua
on_player_receive_fields = function(self, player, context, fields)
-- evento della lista testuale: controlla il tipo di evento e imposta il nuovo indice se è cambiata la selezione
if fields.lista_giocatori then
local event = minetest.explode_textlist_event(fields.lista_giocatori)
if event.type == "CHG" then
context.mioadmin_sel_id = event.index
end
-- Al premere "Caccia"
elseif fields.caccia then
local nome_giocatore =
context.myadmin_players[context.mioadmin_sel_id]
if player_name then
minetest.chat_send_player(player:get_player_name(),
"Cacciato " .. nome_giocatore)
minetest.kick_player(nome_giocatore)
end
-- Al premere "Caccia e Banna"
elseif fields.banna then
local nome_giocatore =
context.myadmin_players[context.mioadmin_sel_id]
if player_name then
minetest.chat_send_player(player:get_player_name(),
"Banned " .. player_name)
minetest.ban_player(nome_giocatore)
minetest.kick_player(nome_giocatore, "Banned")
end
end
end,
```
C'è, tuttavia, un problema abbastanza grande a riguardo: chiunque può cacciare o bannare i giocatori!
C'è bisogno di un modo per mostrare questa finestra solo a chi ha i privilegi `kick` e `ban`.
Fortunatamente, SFINV ci permette di farlo!
## Condizioni per la visualizzazione
Si può aggiungere una funzione `is_in_nav` nella definizione della pagina se si desidera gestire quando la pagina deve essere mostrata:
```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,
```
Se si ha bisogno di controllare un solo privilegio o si vuole eseguire un `and`, si bisognerebbe usare `minetest.check_player_privs()` al posto di `get_player_privs`.
Tieni a mente che `is_in_nav` viene chiamato soltanto alla generazione dell'inventario del giocatore.
Questo succede quando un giocatore entra in gioco, si muove tra le finestre, o una mod richiede a SFINV di rigenerare l'inventario.
Ciò significa che hai bisogno di richiedere manualmente la rigenerazione del formspec dell'inventario per ogni evento che potrebbe cambiare il risultato ti `is_in_nav`.
Nel nostro caso, abbiamo bisogno di farlo ogni volta che i permessi `kick` o `ban` vengono assegnati/revocati a un giocatore:
```lua
local function al_cambio_privilegi(nome_target, nome_garante, priv)
if priv ~= "kick" and priv ~= "ban" then
return
end
local giocatore = minetest.get_player_by_name(nome_target)
if not giocatore then
return
end
local contesto = sfinv.get_or_create_context(giocatore)
if contesto.page ~= "mioadmin:mioadmin" then
return
end
sfinv.set_player_inventory_formspec(giocatore, contesto)
end
minetest.register_on_priv_grant(al_cambio_privilegi)
minetest.register_on_priv_revoke(al_cambio_privilegi)
```
## Callback on_enter e on_leave
Un giocatore *entra* in una finestra quando la finestra è selezionata e *esce* dalla finestra quando un'altra finestra è prossima a essere selezionata.
Attenzione che è possibile selezionare più pagine alla volta se viene usata un tema personalizzato.
Si tenga conto, poi, che questi eventi potrebbero non essere innescati dal giocatore, in quanto potrebbe addirittura non avere un formspec aperto in quel momento.
Per esempio, `on_enter` viene chiamato dalla pagina principale anche quando un giocatore entra in gioco, ancor prima che apri l'inventario.
Infine, non è possibile annullare il cambio pagina, in quanto potrebbe potenzialmente confondere il giocatore.
```lua
on_enter = function(self, player, context)
end,
on_leave = function(self, player, context)
end,
```
## Aggiungere a una pagina esistente
Per aggiungere contenuti a una pagina che già esiste, avrai bisogno di sovrascrivere la pagina e modificare il formspec che viene ritornato:
```lua
local vecchia_funzione = sfinv.registered_pages["sfinv:crafting"].get
sfinv.override_page("sfinv:crafting", {
get = function(self, player, context, ...)
local ret = vecchia_funzione(self, player, context, ...)
if type(ret) == "table" then
ret.formspec = ret.formspec .. "label[0,0;Ciao]"
else
-- Retrocompatibilità
ret = ret .. "label[0,0;Ciao]"
end
return ret
end
})
```

View File

@ -8,11 +8,12 @@ layout: base
{% if language == "_it" %}
{% assign language = "it" %}
{% assign links = site.it | sort: "idx" %}
{% assign links = site.it %}
{% else %}
{% assign language = "en" %}
{% assign links = site.en | sort: "idx" %}
{% assign links = site.en %}
{% endif %}
{% assign links = links | where_exp: "item", "item.sitemap != false" | sort: "idx" %}
{% assign num = 0 %}