2020-04-27 16:11:54 +03:00
---
2020-07-11 11:30:46 +03:00
title: "SFINV"
2020-04-27 16:11:54 +03:00
layout: default
root: ../..
idx: 4.7
2020-07-11 11:30:46 +03:00
description: una mod per rendere più semplice la creazione di un inventario complesso
redirect_from: /it/chapters/sfinv.html
2020-04-27 16:11:54 +03:00
---
2020-07-11 11:30:46 +03:00
## Introduzione <!-- omit in toc -->
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
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.
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
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.
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
- [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 )
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
## Registrare una pagina
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
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:
2020-04-27 16:11:54 +03:00
```lua
2020-07-11 11:30:46 +03:00
sfinv.register_page("miamod:ciao", {
title = "Ciao!",
2020-04-27 16:11:54 +03:00
get = function(self, player, context)
return sfinv.make_formspec(player, context,
2020-07-11 11:30:46 +03:00
"label[0.1,0.1;Ciao mondo!]", true)
2020-04-27 16:11:54 +03:00
end
})
```
2020-07-11 11:30:46 +03:00
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.
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
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.
2020-04-27 16:11:54 +03:00
```lua
2020-07-11 11:30:46 +03:00
sfinv.register_page("mioadmin:mioadmin", {
title = "Finestra",
2020-04-27 16:11:54 +03:00
get = function(self, player, context)
2020-07-11 11:30:46 +03:00
local giocatori = {}
context.mioadmin_giocatori = giocatori
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
-- Usare un array per costruire un formspec è decisamente più veloce
2020-04-27 16:11:54 +03:00
local formspec = {
2020-07-11 11:30:46 +03:00
"textlist[0.1,0.1;7.8,3;lista_giocatori;"
2020-04-27 16:11:54 +03:00
}
2020-07-11 11:30:46 +03:00
-- 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
2020-04-27 16:11:54 +03:00
formspec[#formspec + 1] = ","
end
formspec[#formspec + 1] =
2020-07-11 11:30:46 +03:00
minetest.formspec_escape(nome_giocatore)
primo = false
2020-04-27 16:11:54 +03:00
end
formspec[#formspec + 1] = "]"
2020-07-11 11:30:46 +03:00
-- 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]"
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
-- Avvolge il formspec nella disposizione di SFINV
-- (es: aggiunge le linguette delle finestre e lo sfondo)
2020-04-27 16:11:54 +03:00
return sfinv.make_formspec(player, context,
table.concat(formspec, ""), false)
end,
})
```
2020-07-11 11:30:46 +03:00
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.
2020-04-27 16:11:54 +03:00
< figure >
2020-07-11 11:30:46 +03:00
< img src = "{{ page.root }}//static/sfinv_admin_fs.png" alt = "Pagina per gli amministratori" >
2020-04-27 16:11:54 +03:00
< / figure >
2020-07-11 11:30:46 +03:00
## Ricevere eventi
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
Puoi ricevere eventi formspec tramite l'aggiunta della funzione `on_player_receive_fields` nella definizione SFINV.
2020-04-27 16:11:54 +03:00
```lua
on_player_receive_fields = function(self, player, context, fields)
2020-07-11 11:30:46 +03:00
-- TODO: implementarlo
2020-04-27 16:11:54 +03:00
end,
```
2020-07-11 11:30:46 +03:00
`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.
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
Implementiamo ora `on_player_receive_fields` nella mod:
2020-04-27 16:11:54 +03:00
```lua
on_player_receive_fields = function(self, player, context, fields)
2020-07-11 11:30:46 +03:00
-- 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)
2020-04-27 16:11:54 +03:00
if event.type == "CHG" then
2020-07-11 11:30:46 +03:00
context.mioadmin_sel_id = event.index
2020-04-27 16:11:54 +03:00
end
2020-07-11 11:30:46 +03:00
-- Al premere "Caccia"
elseif fields.caccia then
local nome_giocatore =
context.myadmin_players[context.mioadmin_sel_id]
2020-04-27 16:11:54 +03:00
if player_name then
minetest.chat_send_player(player:get_player_name(),
2020-07-11 11:30:46 +03:00
"Cacciato " .. nome_giocatore)
minetest.kick_player(nome_giocatore)
2020-04-27 16:11:54 +03:00
end
2020-07-11 11:30:46 +03:00
-- Al premere "Caccia e Banna"
elseif fields.banna then
local nome_giocatore =
context.myadmin_players[context.mioadmin_sel_id]
2020-04-27 16:11:54 +03:00
if player_name then
minetest.chat_send_player(player:get_player_name(),
"Banned " .. player_name)
2020-07-11 11:30:46 +03:00
minetest.ban_player(nome_giocatore)
minetest.kick_player(nome_giocatore, "Banned")
2020-04-27 16:11:54 +03:00
end
end
end,
```
2020-07-11 11:30:46 +03:00
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!
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
## Condizioni per la visualizzazione
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
Si può aggiungere una funzione `is_in_nav` nella definizione della pagina se si desidera gestire quando la pagina deve essere mostrata:
2020-04-27 16:11:54 +03:00
```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,
```
2020-07-11 11:30:46 +03:00
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` .
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
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.
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
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:
2020-04-27 16:11:54 +03:00
```lua
2020-07-11 11:30:46 +03:00
local function al_cambio_privilegi(nome_target, nome_garante, priv)
2020-04-27 16:11:54 +03:00
if priv ~= "kick" and priv ~= "ban" then
return
end
2020-07-11 11:30:46 +03:00
local giocatore = minetest.get_player_by_name(nome_target)
if not giocatore then
2020-04-27 16:11:54 +03:00
return
end
2020-07-11 11:30:46 +03:00
local contesto = sfinv.get_or_create_context(giocatore)
if contesto.page ~= "mioadmin:mioadmin" then
2020-04-27 16:11:54 +03:00
return
end
2020-07-11 11:30:46 +03:00
sfinv.set_player_inventory_formspec(giocatore, contesto)
2020-04-27 16:11:54 +03:00
end
2020-07-11 11:30:46 +03:00
minetest.register_on_priv_grant(al_cambio_privilegi)
minetest.register_on_priv_revoke(al_cambio_privilegi)
2020-04-27 16:11:54 +03:00
```
2020-07-11 11:30:46 +03:00
## Callback on_enter e on_leave
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
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.
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
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.
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
Infine, non è possibile annullare il cambio pagina, in quanto potrebbe potenzialmente confondere il giocatore.
2020-04-27 16:11:54 +03:00
```lua
on_enter = function(self, player, context)
end,
on_leave = function(self, player, context)
end,
```
2020-07-11 11:30:46 +03:00
## Aggiungere a una pagina esistente
2020-04-27 16:11:54 +03:00
2020-07-11 11:30:46 +03:00
Per aggiungere contenuti a una pagina che già esiste, avrai bisogno di sovrascrivere la pagina e modificare il formspec che viene ritornato:
2020-04-27 16:11:54 +03:00
```lua
2020-07-11 11:30:46 +03:00
local vecchia_funzione = sfinv.registered_pages["sfinv:crafting"].get
2020-04-27 16:11:54 +03:00
sfinv.override_page("sfinv:crafting", {
get = function(self, player, context, ...)
2020-07-11 11:30:46 +03:00
local ret = vecchia_funzione(self, player, context, ...)
2020-04-27 16:11:54 +03:00
if type(ret) == "table" then
2020-07-11 11:30:46 +03:00
ret.formspec = ret.formspec .. "label[0,0;Ciao]"
2020-04-27 16:11:54 +03:00
else
2020-07-11 11:30:46 +03:00
-- Retrocompatibilità
ret = ret .. "label[0,0;Ciao]"
2020-04-27 16:11:54 +03:00
end
return ret
end
})
```