Skip to content

Commit d42ae71

Browse files
rubenwardyparamat
authored andcommittedNov 27, 2016
Sfinv: Add sfinv to allow tabs to be added to the inventory
1 parent e837621 commit d42ae71

File tree

8 files changed

+483
-234
lines changed

8 files changed

+483
-234
lines changed
 

‎game_api.txt

+105-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,17 @@ Beds API
7070
Creative API
7171
------------
7272

73-
A global string called `creative.formspec_add` was added which allows mods to add additional formspec elements onto the default creative inventory formspec to be drawn after each update.
73+
Use `creative.register_tab(name, title, items)` to add a tab with filtered items.
74+
For example,
75+
76+
creative.register_tab("tools", "Tools", minetest.registered_tools)
77+
78+
is used to show all tools. Name is used in the sfinv page name, title is the
79+
human readable title.
80+
81+
The contents of `creative.formspec_add` is appended to every creative inventory
82+
page. Mods can use it to add additional formspec elements onto the default
83+
creative inventory formspec to be drawn after each update.
7484

7585
Doors API
7686
---------
@@ -391,6 +401,100 @@ set a players home position and teleport a player to home position.
391401
* return value: false if player cannot be sent home, otherwise true
392402

393403

404+
Sfinv API
405+
---------
406+
407+
### sfinv Methods
408+
409+
* sfinv.set_player_inventory_formspec(player, context) - builds page formspec
410+
and calls set_inventory_formspec().
411+
If context is nil, it is either found or created.
412+
* sfinv.get_formspec(player, context) - builds current page's formspec
413+
* sfinv.get_nav_fs(player, context, nav, current_idx) - see above
414+
* sfinv.make_formspec(player, context, content, show_inv, size) - adds a theme to a formspec
415+
* show_inv, defaults to false. Whether to show the player's main inventory
416+
* size, defaults to `size[8,8.6]` if not specified
417+
* sfinv.register_page(name, def) - register a page, see section below
418+
* sfinv.override_page(name, def) - overrides fields of an page registered with register_page.
419+
* Note: Page must already be defined, (opt)depend on the mod defining it.
420+
421+
### sfinv Members
422+
423+
* pages - table of pages[pagename] = def
424+
* pages_unordered - array table of pages in order of addition (used to build navigation tabs).
425+
* homepage_name - name of default page
426+
* contexts - contexts[playername] = player_context
427+
* enabled - set to false to disable. Good for inventory rehaul mods like unified inventory
428+
429+
### Context
430+
431+
A table with these keys:
432+
433+
* page - current page name
434+
* nav - a list of page names
435+
* nav_titles - a list of page titles
436+
* nav_idx - current nav index (in nav and nav_titles)
437+
* any thing you want to store
438+
* sfinv will clear the stored data on log out / log in
439+
440+
### sfinv.register_page
441+
442+
sfinv.register_page(name, def)
443+
444+
def is a table containing:
445+
446+
* `title` - human readable page name (required)
447+
* `get(self, player, context)` - returns a formspec string. See formspec variables. (required)
448+
* `is_in_nav(self, player, context)` - return true to show in the navigation (the tab header, by default)
449+
* `on_player_receive_fields(self, player, context, fields)` - on formspec submit.
450+
* `on_enter(self, player, context)` - called when the player changes pages, usually using the tabs.
451+
* `on_leave(self, player, context)` - when leaving this page to go to another, called before other's on_enter
452+
453+
### get formspec
454+
455+
Use sfinv.make_formspec to apply a layout:
456+
457+
return sfinv.make_formspec(player, context, [[
458+
list[current_player;craft;1.75,0.5;3,3;]
459+
list[current_player;craftpreview;5.75,1.5;1,1;]
460+
image[4.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]
461+
listring[current_player;main]
462+
listring[current_player;craft]
463+
image[0,4.25;1,1;gui_hb_bg.png]
464+
image[1,4.25;1,1;gui_hb_bg.png]
465+
image[2,4.25;1,1;gui_hb_bg.png]
466+
image[3,4.25;1,1;gui_hb_bg.png]
467+
image[4,4.25;1,1;gui_hb_bg.png]
468+
image[5,4.25;1,1;gui_hb_bg.png]
469+
image[6,4.25;1,1;gui_hb_bg.png]
470+
image[7,4.25;1,1;gui_hb_bg.png]
471+
]], true)
472+
473+
See above (methods section) for more options.
474+
475+
### Customising themes
476+
477+
Simply override this function to change the navigation:
478+
479+
function sfinv.get_nav_fs(player, context, nav, current_idx)
480+
return "navformspec"
481+
end
482+
483+
And override this function to change the layout:
484+
485+
function sfinv.make_formspec(player, context, content, show_inv, size)
486+
local tmp = {
487+
size or "size[8,8.6]",
488+
theme_main,
489+
sfinv.get_nav_fs(player, context, context.nav_titles, context.nav_idx),
490+
content
491+
}
492+
if show_inv then
493+
tmp[4] = theme_inv
494+
end
495+
return table.concat(tmp, "")
496+
end
497+
394498
Stairs API
395499
----------
396500

‎mods/creative/depends.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
default
2+
sfinv

‎mods/creative/init.lua

+4-233
Original file line numberDiff line numberDiff line change
@@ -1,237 +1,8 @@
1-
-- minetest/creative/init.lua
1+
dofile(minetest.get_modpath("creative") .. "/inventory.lua")
22

3-
creative = {}
4-
local player_inventory = {}
5-
local creative_mode = minetest.setting_getbool("creative_mode")
6-
7-
-- Create detached creative inventory after loading all mods
8-
creative.init_creative_inventory = function(owner)
9-
local owner_name = owner:get_player_name()
10-
player_inventory[owner_name] = {
11-
size = 0,
12-
filter = "",
13-
start_i = 0,
14-
tab_id = 2,
15-
}
16-
17-
minetest.create_detached_inventory("creative_" .. owner_name, {
18-
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
19-
if creative_mode and not to_list == "main" then
20-
return count
21-
else
22-
return 0
23-
end
24-
end,
25-
allow_put = function(inv, listname, index, stack, player)
26-
return 0
27-
end,
28-
allow_take = function(inv, listname, index, stack, player)
29-
if creative_mode then
30-
return -1
31-
else
32-
return 0
33-
end
34-
end,
35-
on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
36-
end,
37-
on_put = function(inv, listname, index, stack, player)
38-
end,
39-
on_take = function(inv, listname, index, stack, player)
40-
local player_name, stack_name = player:get_player_name(), stack:get_name()
41-
--print(player_name .. " takes item from creative inventory; listname = " .. listname .. ", index = " .. index .. ", stack = " .. dump(stack:to_table()))
42-
if stack then
43-
minetest.log("action", player_name .. " takes " .. stack_name .. " from creative inventory")
44-
--print("Stack name: " .. stack_name .. ", Stack count: " .. stack:get_count())
45-
end
46-
end,
47-
})
48-
49-
creative.update_creative_inventory(owner_name)
50-
--print("creative inventory size: " .. player_inventory[player_name].size)
51-
end
52-
53-
local function tab_category(tab_id)
54-
local id_category = {
55-
nil, -- Reserved for crafting tab.
56-
minetest.registered_items,
57-
minetest.registered_nodes,
58-
minetest.registered_tools,
59-
minetest.registered_craftitems
60-
}
61-
62-
-- If index out of range, show default ("All") page.
63-
return id_category[tab_id] or id_category[2]
64-
end
65-
66-
function creative.update_creative_inventory(player_name)
67-
local creative_list = {}
68-
local player_inv = minetest.get_inventory({type = "detached", name = "creative_" .. player_name})
69-
local inv = player_inventory[player_name]
70-
71-
for name, def in pairs(tab_category(inv.tab_id)) do
72-
if not (def.groups.not_in_creative_inventory == 1) and
73-
def.description and def.description ~= "" and
74-
(def.name:find(inv.filter, 1, true) or
75-
def.description:lower():find(inv.filter, 1, true)) then
76-
creative_list[#creative_list+1] = name
77-
end
78-
end
79-
80-
table.sort(creative_list)
81-
player_inv:set_size("main", #creative_list)
82-
player_inv:set_list("main", creative_list)
83-
inv.size = #creative_list
84-
end
85-
86-
-- Create the trash field
87-
local trash = minetest.create_detached_inventory("creative_trash", {
88-
-- Allow the stack to be placed and remove it in on_put()
89-
-- This allows the creative inventory to restore the stack
90-
allow_put = function(inv, listname, index, stack, player)
91-
if creative_mode then
92-
return stack:get_count()
93-
else
94-
return 0
95-
end
96-
end,
97-
on_put = function(inv, listname)
98-
inv:set_list(listname, {})
99-
end,
100-
})
101-
trash:set_size("main", 1)
102-
103-
creative.formspec_add = ""
104-
105-
creative.set_creative_formspec = function(player, start_i)
106-
local player_name = player:get_player_name()
107-
local inv = player_inventory[player_name]
108-
local pagenum = math.floor(start_i / (3*8) + 1)
109-
local pagemax = math.ceil(inv.size / (3*8))
110-
111-
player:set_inventory_formspec([[
112-
size[8,8.6]
113-
image[4.06,3.4;0.8,0.8;creative_trash_icon.png]
114-
list[current_player;main;0,4.7;8,1;]
115-
list[current_player;main;0,5.85;8,3;8]
116-
list[detached:creative_trash;main;4,3.3;1,1;]
117-
listring[]
118-
tablecolumns[color;text;color;text]
119-
tableoptions[background=#00000000;highlight=#00000000;border=false]
120-
button[5.4,3.2;0.8,0.9;creative_prev;<]
121-
button[7.25,3.2;0.8,0.9;creative_next;>]
122-
button[2.1,3.4;0.8,0.5;creative_search;?]
123-
button[2.75,3.4;0.8,0.5;creative_clear;X]
124-
tooltip[creative_search;Search]
125-
tooltip[creative_clear;Reset]
126-
listring[current_player;main]
127-
]] ..
128-
"field[0.3,3.5;2.2,1;creative_filter;;" .. minetest.formspec_escape(inv.filter) .. "]" ..
129-
"field_close_on_enter[creative_filter;false]" ..
130-
"listring[detached:creative_" .. player_name .. ";main]" ..
131-
"tabheader[0,0;creative_tabs;Crafting,All,Nodes,Tools,Items;" .. tostring(inv.tab_id) .. ";true;false]" ..
132-
"list[detached:creative_" .. player_name .. ";main;0,0;8,3;" .. tostring(start_i) .. "]" ..
133-
"table[6.05,3.35;1.15,0.5;pagenum;#FFFF00," .. tostring(pagenum) .. ",#FFFFFF,/ " .. tostring(pagemax) .. "]" ..
134-
default.get_hotbar_bg(0,4.7) ..
135-
default.gui_bg .. default.gui_bg_img .. default.gui_slots
136-
.. creative.formspec_add
137-
)
138-
end
139-
140-
creative.set_crafting_formspec = function(player)
141-
player:set_inventory_formspec([[
142-
size[8,8.6]
143-
list[current_player;craft;2,0.75;3,3;]
144-
list[current_player;craftpreview;6,1.75;1,1;]
145-
list[current_player;main;0,4.7;8,1;]
146-
list[current_player;main;0,5.85;8,3;8]
147-
list[detached:creative_trash;main;0,2.75;1,1;]
148-
image[0.06,2.85;0.8,0.8;creative_trash_icon.png]
149-
image[5,1.75;1,1;gui_furnace_arrow_bg.png^[transformR270]
150-
tabheader[0,0;creative_tabs;Crafting,All,Nodes,Tools,Items;1;true;false]
151-
listring[current_player;main]
152-
listring[current_player;craft]
153-
]] ..
154-
default.get_hotbar_bg(0,4.7) ..
155-
default.gui_bg .. default.gui_bg_img .. default.gui_slots
156-
)
157-
end
158-
159-
minetest.register_on_joinplayer(function(player)
160-
-- If in creative mode, modify player's inventory forms
161-
if not creative_mode then
162-
return
163-
end
164-
creative.init_creative_inventory(player)
165-
creative.set_creative_formspec(player, 0)
166-
end)
167-
168-
minetest.register_on_player_receive_fields(function(player, formname, fields)
169-
if formname ~= "" or not creative_mode then
170-
return
171-
end
172-
173-
local player_name = player:get_player_name()
174-
local inv = player_inventory[player_name]
175-
176-
-- If creative is turned on mid game
177-
if not inv then
178-
creative.init_creative_inventory(player)
179-
creative.set_creative_formspec(player, 0)
180-
return
181-
end
182-
183-
if fields.quit then
184-
if inv.tab_id == 1 then
185-
creative.set_crafting_formspec(player)
186-
end
187-
elseif fields.creative_tabs then
188-
local tab = tonumber(fields.creative_tabs)
189-
inv.tab_id = tab
190-
player_inventory[player_name].start_i = 0
191-
192-
if tab == 1 then
193-
creative.set_crafting_formspec(player)
194-
else
195-
creative.update_creative_inventory(player_name)
196-
creative.set_creative_formspec(player, 0)
197-
end
198-
elseif fields.creative_clear then
199-
player_inventory[player_name].start_i = 0
200-
inv.filter = ""
201-
creative.update_creative_inventory(player_name)
202-
creative.set_creative_formspec(player, 0)
203-
elseif fields.creative_search or
204-
fields.key_enter_field == "creative_filter" then
205-
player_inventory[player_name].start_i = 0
206-
inv.filter = fields.creative_filter:lower()
207-
creative.update_creative_inventory(player_name)
208-
creative.set_creative_formspec(player, 0)
209-
else
210-
local start_i = player_inventory[player_name].start_i or 0
211-
212-
if fields.creative_prev then
213-
start_i = start_i - 3*8
214-
if start_i < 0 then
215-
start_i = inv.size - (inv.size % (3*8))
216-
if inv.size == start_i then
217-
start_i = math.max(0, inv.size - (3*8))
218-
end
219-
end
220-
elseif fields.creative_next then
221-
start_i = start_i + 3*8
222-
if start_i >= inv.size then
223-
start_i = 0
224-
end
225-
end
226-
227-
player_inventory[player_name].start_i = start_i
228-
creative.set_creative_formspec(player, start_i)
229-
end
230-
end)
231-
232-
if creative_mode then
233-
local digtime = 42
234-
local caps = {times = {digtime, digtime, digtime}, uses = 0, maxlevel = 256}
3+
if minetest.setting_getbool("creative_mode") then
4+
local digtime = 0.5
5+
local caps = {times = {digtime, digtime, digtime}, uses = 0, maxlevel = 3}
2356

2367
minetest.register_item(":", {
2378
type = "none",

‎mods/creative/inventory.lua

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
creative = {}
2+
local player_inventory = {}
3+
4+
function creative.init_creative_inventory(player)
5+
local player_name = player:get_player_name()
6+
player_inventory[player_name] = {
7+
size = 0,
8+
filter = "",
9+
start_i = 0
10+
}
11+
12+
minetest.create_detached_inventory("creative_" .. player_name, {
13+
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player2)
14+
if not to_list == "main" then
15+
return count
16+
else
17+
return 0
18+
end
19+
end,
20+
allow_put = function(inv, listname, index, stack, player2)
21+
return 0
22+
end,
23+
allow_take = function(inv, listname, index, stack, player2)
24+
return -1
25+
end,
26+
on_move = function(inv, from_list, from_index, to_list, to_index, count, player2)
27+
end,
28+
on_put = function(inv, listname, index, stack, player2)
29+
end,
30+
on_take = function(inv, listname, index, stack, player2)
31+
if stack and stack:get_count() > 0 then
32+
minetest.log("action", player_name .. " takes " .. stack:get_name().. " from creative inventory")
33+
end
34+
end,
35+
})
36+
37+
creative.update_creative_inventory(player_name, minetest.registered_items)
38+
end
39+
40+
function creative.update_creative_inventory(player_name, tab_content)
41+
local creative_list = {}
42+
local player_inv = minetest.get_inventory({type = "detached", name = "creative_" .. player_name})
43+
local inv = player_inventory[player_name]
44+
if not inv then
45+
creative.init_creative_inventory(minetest.get_player_by_name(player_name))
46+
end
47+
48+
for name, def in pairs(tab_content) do
49+
if not (def.groups.not_in_creative_inventory == 1) and
50+
def.description and def.description ~= "" and
51+
(def.name:find(inv.filter, 1, true) or
52+
def.description:lower():find(inv.filter, 1, true)) then
53+
creative_list[#creative_list+1] = name
54+
end
55+
end
56+
57+
table.sort(creative_list)
58+
player_inv:set_size("main", #creative_list)
59+
player_inv:set_list("main", creative_list)
60+
inv.size = #creative_list
61+
end
62+
63+
-- Create the trash field
64+
local trash = minetest.create_detached_inventory("creative_trash", {
65+
-- Allow the stack to be placed and remove it in on_put()
66+
-- This allows the creative inventory to restore the stack
67+
allow_put = function(inv, listname, index, stack, player)
68+
return stack:get_count()
69+
end,
70+
on_put = function(inv, listname)
71+
inv:set_list(listname, {})
72+
end,
73+
})
74+
trash:set_size("main", 1)
75+
76+
creative.formspec_add = ""
77+
78+
function creative.register_tab(name, title, items)
79+
sfinv.register_page("creative:" .. name, {
80+
title = title,
81+
is_in_nav = function(self, player, context)
82+
return minetest.setting_getbool("creative_mode")
83+
end,
84+
get = function(self, player, context)
85+
local player_name = player:get_player_name()
86+
creative.update_creative_inventory(player_name, items)
87+
local inv = player_inventory[player_name]
88+
local start_i = inv.start_i or 0
89+
local pagenum = math.floor(start_i / (3*8) + 1)
90+
local pagemax = math.ceil(inv.size / (3*8))
91+
return sfinv.make_formspec(player, context,
92+
"label[6.2,3.35;" .. minetest.colorize("#FFFF00", tostring(pagenum)) .. " / " .. tostring(pagemax) .. "]" ..
93+
[[
94+
image[4.06,3.4;0.8,0.8;creative_trash_icon.png]
95+
listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]
96+
list[current_player;main;0,4.7;8,1;]
97+
list[current_player;main;0,5.85;8,3;8]
98+
list[detached:creative_trash;main;4,3.3;1,1;]
99+
listring[]
100+
button[5.4,3.2;0.8,0.9;creative_prev;<]
101+
button[7.25,3.2;0.8,0.9;creative_next;>]
102+
button[2.1,3.4;0.8,0.5;creative_search;?]
103+
button[2.75,3.4;0.8,0.5;creative_clear;X]
104+
tooltip[creative_search;Search]
105+
tooltip[creative_clear;Reset]
106+
listring[current_player;main]
107+
field_close_on_enter[creative_filter;false]
108+
]] ..
109+
"field[0.3,3.5;2.2,1;creative_filter;;" .. minetest.formspec_escape(inv.filter) .. "]" ..
110+
"listring[detached:creative_" .. player_name .. ";main]" ..
111+
"list[detached:creative_" .. player_name .. ";main;0,0;8,3;" .. tostring(start_i) .. "]" ..
112+
default.get_hotbar_bg(0,4.7) ..
113+
default.gui_bg .. default.gui_bg_img .. default.gui_slots
114+
.. creative.formspec_add, false)
115+
end,
116+
on_enter = function(self, player, context)
117+
local player_name = player:get_player_name()
118+
local inv = player_inventory[player_name]
119+
if inv then
120+
inv.start_i = 0
121+
end
122+
end,
123+
on_player_receive_fields = function(self, player, context, fields)
124+
local player_name = player:get_player_name()
125+
local inv = player_inventory[player_name]
126+
assert(inv)
127+
128+
if fields.creative_clear then
129+
inv.start_i = 0
130+
inv.filter = ""
131+
creative.update_creative_inventory(player_name, items)
132+
sfinv.set_player_inventory_formspec(player, context)
133+
elseif fields.creative_search or
134+
fields.key_enter_field == "creative_filter" then
135+
inv.start_i = 0
136+
inv.filter = fields.creative_filter:lower()
137+
creative.update_creative_inventory(player_name, items)
138+
sfinv.set_player_inventory_formspec(player, context)
139+
elseif not fields.quit then
140+
local start_i = inv.start_i or 0
141+
142+
if fields.creative_prev then
143+
start_i = start_i - 3*8
144+
if start_i < 0 then
145+
start_i = inv.size - (inv.size % (3*8))
146+
if inv.size == start_i then
147+
start_i = math.max(0, inv.size - (3*8))
148+
end
149+
end
150+
elseif fields.creative_next then
151+
start_i = start_i + 3*8
152+
if start_i >= inv.size then
153+
start_i = 0
154+
end
155+
end
156+
157+
inv.start_i = start_i
158+
sfinv.set_player_inventory_formspec(player, context)
159+
end
160+
end
161+
})
162+
end
163+
164+
minetest.register_on_joinplayer(function(player)
165+
creative.init_creative_inventory(player)
166+
end)
167+
168+
creative.register_tab("all", "All", minetest.registered_items)
169+
creative.register_tab("nodes", "Nodes", minetest.registered_nodes)
170+
creative.register_tab("tools", "Tools", minetest.registered_tools)
171+
creative.register_tab("craftitems", "Items", minetest.registered_craftitems)

‎mods/sfinv/README.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Simple Fast Inventory
2+
====================
3+
4+
![SFINV Screeny](https://cdn.pbrd.co/images/1yQhd1TI.png)
5+
6+
A cleaner, simpler, solution to having an advanced inventory in Minetest.
7+
8+
Written by rubenwardy.
9+
License: MIT
10+
11+
See game_api.txt for this mod's API
12+
13+
License of source code and media files:
14+
---------------------------------------
15+
Copyright (C) 2016 rubenwardy <rubenwardy@gmail.com>
16+
17+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
18+
19+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
20+
21+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

‎mods/sfinv/api.lua

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
sfinv = {
2+
pages = {},
3+
pages_unordered = {},
4+
homepage_name = "sfinv:crafting",
5+
contexts = {},
6+
enabled = true
7+
}
8+
9+
function sfinv.register_page(name, def)
10+
assert(name, "Invalid sfinv page. Requires a name")
11+
assert(def, "Invalid sfinv page. Requires a def[inition] table")
12+
assert(def.get, "Invalid sfinv page. Def requires a get function.")
13+
assert(not sfinv.pages[name], "Attempt to register already registered sfinv page " .. dump(name))
14+
15+
sfinv.pages[name] = def
16+
def.name = name
17+
table.insert(sfinv.pages_unordered, def)
18+
end
19+
20+
function sfinv.override_page(name, def)
21+
assert(name, "Invalid sfinv page override. Requires a name")
22+
assert(def, "Invalid sfinv page override. Requires a def[inition] table")
23+
local page = sfinv.pages[name]
24+
assert(page, "Attempt to override sfinv page " .. dump(name) .. " which does not exist.")
25+
for key, value in pairs(def) do
26+
page[key] = value
27+
end
28+
end
29+
30+
function sfinv.get_nav_fs(player, context, nav, current_idx)
31+
-- Only show tabs if there is more than one page
32+
if #nav > 1 then
33+
return "tabheader[0,0;tabs;" .. table.concat(nav, ",") .. ";" .. current_idx .. ";true;false]"
34+
else
35+
return ""
36+
end
37+
end
38+
39+
local theme_main = "bgcolor[#080808BB;true]" .. default.gui_bg ..
40+
default.gui_bg_img
41+
42+
local theme_inv = default.gui_slots .. [[
43+
list[current_player;main;0,4.7;8,1;]
44+
list[current_player;main;0,5.85;8,3;8]
45+
]]
46+
47+
function sfinv.make_formspec(player, context, content, show_inv, size)
48+
local tmp = {
49+
size or "size[8,8.6]",
50+
theme_main,
51+
sfinv.get_nav_fs(player, context, context.nav_titles, context.nav_idx),
52+
content
53+
}
54+
if show_inv then
55+
tmp[#tmp + 1] = theme_inv
56+
end
57+
return table.concat(tmp, "")
58+
end
59+
60+
function sfinv.get_formspec(player, context)
61+
-- Generate navigation tabs
62+
local nav = {}
63+
local nav_ids = {}
64+
local current_idx = 1
65+
for i, pdef in pairs(sfinv.pages_unordered) do
66+
if not pdef.is_in_nav or pdef:is_in_nav(player, context) then
67+
nav[#nav + 1] = pdef.title
68+
nav_ids[#nav_ids + 1] = pdef.name
69+
if pdef.name == context.page then
70+
current_idx = i
71+
end
72+
end
73+
end
74+
context.nav = nav_ids
75+
context.nav_titles = nav
76+
context.nav_idx = current_idx
77+
78+
-- Generate formspec
79+
local page = sfinv.pages[context.page] or sfinv.pages["404"]
80+
if page then
81+
return page:get(player, context)
82+
else
83+
local old_page = context.page
84+
context.page = sfinv.homepage_name
85+
assert(sfinv.pages[context.page], "[sfinv] Invalid homepage")
86+
minetest.log("warning", "[sfinv] Couldn't find " .. dump(old_page) .. " so using switching to homepage")
87+
return sfinv.get_formspec(player, context)
88+
end
89+
end
90+
91+
function sfinv.set_player_inventory_formspec(player, context)
92+
if not context then
93+
local name = player:get_player_name()
94+
context = sfinv.contexts[name]
95+
if not context then
96+
context = {
97+
page = sfinv.homepage_name
98+
}
99+
sfinv.contexts[name] = context
100+
end
101+
end
102+
103+
local fs = sfinv.get_formspec(player, context)
104+
player:set_inventory_formspec(fs)
105+
end
106+
107+
minetest.register_on_joinplayer(function(player)
108+
if sfinv.enabled then
109+
minetest.after(0.5, function()
110+
sfinv.set_player_inventory_formspec(player)
111+
end)
112+
end
113+
end)
114+
115+
minetest.register_on_leaveplayer(function(player)
116+
sfinv.contexts[player:get_player_name()] = nil
117+
end)
118+
119+
minetest.register_on_player_receive_fields(function(player, formname, fields)
120+
if formname ~= "" or not sfinv.enabled then
121+
return false
122+
end
123+
124+
-- Get Context
125+
local name = player:get_player_name()
126+
local context = sfinv.contexts[name]
127+
if not context then
128+
sfinv.set_player_inventory_formspec(player)
129+
return false
130+
end
131+
132+
-- Handle Events
133+
if fields.tabs and context.nav then
134+
local tid = tonumber(fields.tabs)
135+
if tid and tid > 0 then
136+
local id = context.nav[tid]
137+
local page = sfinv.pages[id]
138+
if id and page then
139+
local oldpage = sfinv.pages[context.page]
140+
if oldpage and oldpage.on_leave then
141+
oldpage:on_leave(player, context)
142+
end
143+
context.page = id
144+
if page.on_enter then
145+
page:on_enter(player, context)
146+
end
147+
sfinv.set_player_inventory_formspec(player, context)
148+
end
149+
end
150+
return
151+
end
152+
153+
-- Pass to page
154+
local page = sfinv.pages[context.page]
155+
if page and page.on_player_receive_fields then
156+
return page:on_player_receive_fields(player, context, fields)
157+
end
158+
end)

‎mods/sfinv/depends.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
default

‎mods/sfinv/init.lua

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
dofile(minetest.get_modpath("sfinv") .. "/api.lua")
2+
3+
sfinv.register_page("sfinv:crafting", {
4+
title = "Crafting",
5+
get = function(self, player, context)
6+
return sfinv.make_formspec(player, context, [[
7+
list[current_player;craft;1.75,0.5;3,3;]
8+
list[current_player;craftpreview;5.75,1.5;1,1;]
9+
image[4.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]
10+
listring[current_player;main]
11+
listring[current_player;craft]
12+
image[0,4.75;1,1;gui_hb_bg.png]
13+
image[1,4.75;1,1;gui_hb_bg.png]
14+
image[2,4.75;1,1;gui_hb_bg.png]
15+
image[3,4.75;1,1;gui_hb_bg.png]
16+
image[4,4.75;1,1;gui_hb_bg.png]
17+
image[5,4.75;1,1;gui_hb_bg.png]
18+
image[6,4.75;1,1;gui_hb_bg.png]
19+
image[7,4.75;1,1;gui_hb_bg.png]
20+
]], true)
21+
end
22+
})

0 commit comments

Comments
 (0)
Please sign in to comment.