Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed
-- Finally Enough Items-- Copyright (C) 2026 mrkubax10-- This program is free software: you can redistribute it and/or modify-- it under the terms of the GNU Affero General Public License as published by-- the Free Software Foundation, either version 3 of the License, or-- (at your option) any later version.-- This program is distributed in the hope that it will be useful,-- but WITHOUT ANY WARRANTY; without even the implied warranty of-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-- GNU Affero General Public License for more details.-- You should have received a copy of the GNU Affero General Public License-- along with this program. If not, see <https://www.gnu.org/licenses/>.local prev_inventory_formspec_values={}local update_elapsed = 0-- Extracts next number from string from the beginninglocal function scan_number(str)local begin_index = 0local end_index = 0local collect = falselocal index = 1for ch in string.gmatch(str, ".") doif collect thenif not string.match(ch, "%d") and ch~="." thenend_index = indexbreakendelseif string.match(ch, "%d") thenbegin_index = indexcollect = trueendendindex = index+1endif begin_index==end_index thenreturn 0, strendreturn tonumber(string.sub(str, begin_index, end_index-1)), string.sub(str, end_index+1)endlocal function parse_formspec_information(formspec)local width = 0local height = 0local _, size_end = string.find(formspec, "size%[")if size_end thenlocal size_pattern = string.sub(formspec, size_end)width, size_pattern = scan_number(size_pattern)height, size_pattern = scan_number(size_pattern)endlocal version = 1local _, version_end = string.find(formspec, "formspec_version%[")if version_end thenlocal version_pattern = string.sub(formspec, version_end)version, _ = scan_number(version_pattern)endlocal real_coordinates = falselocal _, real_coordinates_end = string.find(formspec, "real_coordinates%[")if real_coordinates_end then-- Check for true keywordlocal real_coordinates_pattern = string.sub(formspec, real_coordinates_end, real_coordinates_end+4)real_coordinates = real_coordinates_pattern=="true"endreturn {width = width,height = height,legacy_coordinates = version==1 and not real_coordinates}endlocal function determine_anchor(window_info, inv_formspec_info)local element_spacing = inv_formspec_info.legacy_coordinates and 0.25 or 0local formspec_center_x = inv_formspec_info.width/2local formspec_center_y = inv_formspec_info.height/2local window_center_x = window_info.max_formspec_size.x/2local window_center_y = window_info.max_formspec_size.y/2return {x = formspec_center_x-element_spacing+window_center_x-window_center_x*element_spacing,y = formspec_center_y-element_spacing-window_center_y+window_center_y*element_spacing}endlocal function create_items_view(player, prev_inventory_formspec)local window_info = minetest.get_player_window_information(player:get_player_name())-- There is a brief moment when the player is still joining where get_player_window_information returns nilif not window_info thenreturn ""endlocal inv_formspec_info = parse_formspec_information(player:get_formspec_prepend()..prev_inventory_formspec)local items_anchor = determine_anchor(window_info, inv_formspec_info)local formspec = {"style_type[label;noclip=true]","style_type[image_button;noclip=true]",string.format("image_button[%f,%f;1,1;default_furnace_front.png;button1;]", items_anchor.x, items_anchor.y),}return table.concat(formspec, "")endlocal function update_if_needed(player, prev_inventory_formspec)player:set_inventory_formspec(prev_inventory_formspec..create_items_view(player, prev_inventory_formspec))end-- This is a kind of hacky way of registering in on_mods_loaded to make sure that our on_joinplayer handler is called lastminetest.register_on_mods_loaded(function()minetest.register_on_joinplayer(function(player)prev_inventory_formspec_values[player:get_player_name()] = player:get_inventory_formspec()end)end)minetest.register_on_leaveplayer(function(player)prev_inventory_formspec_values[player:get_player_name()] = nilend)minetest.register_on_player_receive_fields(function(player, formname, fields)-- If player inventory formspec was somehow updated, then change the previous formspec value tooif formname~="" thenreturnendprev_inventory_formspec_values[player:get_player_name()] = player:get_inventory_formspec()update_if_needed(player, player:get_inventory_formspec())end)minetest.register_globalstep(function(dtime)update_elapsed = update_elapsed+dtime-- TODO: Introduce option which will allow to adjust item list updating frequencyif update_elapsed<0.5 thenreturnendupdate_elapsed = 0local players = minetest.get_connected_players()for _,player in ipairs(players) dolocal prev_inventory_formspec = prev_inventory_formspec_values[player:get_player_name()]if prev_inventory_formspec thenupdate_if_needed(player, prev_inventory_formspec)endendend)minetest.register_chatcommand("formspec",{func=function(name)local window_info = minetest.get_player_window_information(name)local formspec={--"formspec_version[2]","size[5,5]","style_type[button;noclip=true]","button[0,0;1,1;button1;]","button[1,0;1,1;button2;]","button[2,0;1,1;button2;]","button[2.25,1;1,1;button2;]"--string.format("button[%f,0;1,1;button1;]", window_info.max_formspec_size.x/2+2.5)}minetest.show_formspec(name, "fei:formspec", table.concat(formspec, ""))end})