From 372f1843b0ea3491281649966ba57bf4ebdf0c1a Mon Sep 17 00:00:00 2001 From: luk3yx Date: Sat, 8 Aug 2020 22:19:27 +0200 Subject: [PATCH] [1.11.0] Add SSCSM Sfinv. --- .luacheckrc | 1 + files/sfinv_sscsm/README.md | 16 +++ files/sfinv_sscsm/api.lua | 251 ++++++++++++++++++++++++++++++++++ files/sfinv_sscsm/depends.txt | 1 + files/sfinv_sscsm/init.lua | 59 ++++++++ files/sfinv_sscsm/license.txt | 25 ++++ files/sfinv_sscsm/mod.conf | 3 + 7 files changed, 356 insertions(+) create mode 100644 files/sfinv_sscsm/README.md create mode 100644 files/sfinv_sscsm/api.lua create mode 100644 files/sfinv_sscsm/depends.txt create mode 100644 files/sfinv_sscsm/init.lua create mode 100644 files/sfinv_sscsm/license.txt create mode 100644 files/sfinv_sscsm/mod.conf diff --git a/.luacheckrc b/.luacheckrc index 328fe1e..02cb665 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -25,6 +25,7 @@ read_globals = { "mobs", "playerphysics", "screwdriver", + "sscsm", -- Silence errors about custom table methods. table = { fields = { "copy", "indexof" } }, -- Silence warnings about accessing undefined fields of global 'math' diff --git a/files/sfinv_sscsm/README.md b/files/sfinv_sscsm/README.md new file mode 100644 index 0000000..90f30e9 --- /dev/null +++ b/files/sfinv_sscsm/README.md @@ -0,0 +1,16 @@ +MultiCraft Game mod: sfinv_sscsm +================================ +See license.txt for license information. + +The SSCSM API replicates [sfinv's API], however all `player` parameters are +removed. + +Returning `false` from an `on_player_receive_fields` callback will send the +fields to the server for processing. + +[sfinv's API]: https://github.com/minetest/minetest_game/blob/5.1.1/game_api.txt#L594 + +Authors of source code +---------------------- +rubenwardy (MIT) +MultiCraft Development Team (MIT) diff --git a/files/sfinv_sscsm/api.lua b/files/sfinv_sscsm/api.lua new file mode 100644 index 0000000..450bd95 --- /dev/null +++ b/files/sfinv_sscsm/api.lua @@ -0,0 +1,251 @@ +sfinv = { + pages = {}, + pages_unordered = {}, + contexts = {}, + enabled = true +} + +local inventory_formspec +local inventory_open = false + +local dump = rawget(_G, "dump") +if not dump then + function dump(raw) + return minetest.serialize(raw):sub(8) + end +end + +function sfinv.register_page(name, def) + assert(name, "Invalid sfinv page. Requires a name") + assert(def, "Invalid sfinv page. Requires a def[inition] table") + assert(def.get, "Invalid sfinv page. Def requires a get function.") + assert(not sfinv.pages[name], "Attempt to register already registered sfinv page " .. dump(name)) + + sfinv.pages[name] = def + def.name = name + table.insert(sfinv.pages_unordered, def) +end + +function sfinv.override_page(name, def) + assert(name, "Invalid sfinv page override. Requires a name") + assert(def, "Invalid sfinv page override. Requires a def[inition] table") + local page = sfinv.pages[name] + assert(page, "Attempt to override sfinv page " .. dump(name) .. " which does not exist.") + for key, value in pairs(def) do + page[key] = value + end +end + +function sfinv.get_nav_fs(context, nav, current_idx) -- luacheck: ignore + -- Only show tabs if there is more than one page + if nav and #nav > 1 then + return "tabheader[0,0;sfinv_nav_tabs;" .. table.concat(nav, ",") .. + ";" .. current_idx .. ";true;false]" + else + return "" + end +end + +local theme_inv = [[ + list[current_player;main;0.01,4.51;9,3;9] + list[current_player;main;0.01,7.74;9,1;] +]] + +local formspec_prepend = "" +function sfinv.make_formspec(context, content, show_inv, size) + local tmp = { + size or "size[9,8.75]", + formspec_prepend, + sfinv.get_nav_fs(context, context.nav_titles, context.nav_idx), + show_inv and theme_inv or "", + content + } + return table.concat(tmp, "") +end + +function sfinv.get_homepage_name() + return "sfinv:inventory" +end + +function sfinv.get_formspec(context) + -- Generate navigation tabs + local nav = {} + local nav_ids = {} + local current_idx = 1 + for _, pdef in pairs(sfinv.pages_unordered) do + if not pdef.is_in_nav or pdef:is_in_nav(context) then + nav[#nav + 1] = pdef.title + nav_ids[#nav_ids + 1] = pdef.name + if pdef.name == context.page then + current_idx = #nav_ids + end + end + end + context.nav = nav_ids + context.nav_titles = nav + context.nav_idx = current_idx + + -- Generate formspec + local page = sfinv.pages[context.page] or sfinv.pages["404"] + if page then + return page:get(context) + else + local old_page = context.page + local home_page = sfinv.get_homepage_name() + + if old_page == home_page then + minetest.log("error", "[sfinv] Couldn't find " .. dump(old_page) .. + ", which is also the old page") + + return "" + end + + context.page = home_page + assert(sfinv.pages[context.page], "[sfinv] Invalid homepage") + minetest.log("warning", "[sfinv] Couldn't find " .. dump(old_page) .. + " so switching to homepage") + + return sfinv.get_formspec(context) + end +end + +function sfinv.get_or_create_context() + local context = sfinv.context + if not context then + context = { + page = sfinv.get_homepage_name() + } + sfinv.context = context + end + return context +end + +function sfinv.set_context(context) + sfinv.context = context +end + +function sfinv.set_player_inventory_formspec(context) + local fs = sfinv.get_formspec(context or sfinv.get_or_create_context()) + inventory_formspec = fs + if inventory_open then + sfinv.open_formspec() + end +end + +function sfinv.set_page(pagename) + local context = sfinv.get_or_create_context() + local oldpage = sfinv.pages[context.page] + if oldpage and oldpage.on_leave then + oldpage:on_leave(context) + end + context.page = pagename + local page = sfinv.pages[pagename] + if not page then + inventory_formspec = nil + elseif page.on_enter then + page:on_enter(context) + end + sfinv.set_player_inventory_formspec(context) +end + +function sfinv.get_page() + local context = sfinv.context + return context and context.page or sfinv.get_homepage_name() +end + +minetest.register_on_formspec_input(function(formname, fields) + if formname ~= "sfinv_sscsm:fs" or not sfinv.enabled then + return false + end + + if fields.quit then + inventory_open = false + end + + -- Get Context + local context = sfinv.context + if not context then + sfinv.set_player_inventory_formspec() + return false + end + + -- Was a tab selected? + if fields.sfinv_nav_tabs and context.nav then + local tid = tonumber(fields.sfinv_nav_tabs) + if tid and tid > 0 then + local id = context.nav[tid] + local page = sfinv.pages[id] + if id and page then + sfinv.set_page(id) + end + end + else + -- Pass event to page + local page = sfinv.pages[context.page] + if page and page.on_player_receive_fields then + local res = page:on_player_receive_fields(context, fields) + if res then + return true + elseif res == false then + -- Pass fields to the server + sscsm.com_send("sfinv_sscsm:fields", fields) + end + end + end +end) + +function sfinv.open_formspec() + inventory_open = true + minetest.show_formspec("sfinv_sscsm:fs", inventory_formspec) +end + +-- Tells the SSCSM that the inventory is no longer open. +function sfinv.inventory_closed() + inventory_open = false +end + +minetest.register_on_inventory_open(function() + if inventory_formspec then + sfinv.open_formspec() + return true + end +end) + +-- Allow mods to defer the takeover of the inventory. +local blockers = 0 +function sfinv.defer_takeover() + blockers = blockers + 1 + return function() + blockers = blockers - 1 + assert(blockers >= 0) + if blockers == 0 then + sfinv.set_player_inventory_formspec() + end + end +end + +sscsm.register_on_mods_loaded(sfinv.defer_takeover()) + +sfinv.register_page("sfinv:inventory", { + get = function(_, player, context) + return sfinv.make_formspec(player, context, "") + end +}) + +sscsm.register_on_com_receive("sfinv_sscsm:set_page", function(msg) + sfinv.set_page(msg[1]) + if msg[2] then + sfinv.open_formspec() + end +end) +sscsm.register_on_com_receive("sfinv_sscsm:open_formspec", sfinv.open_formspec) +sscsm.register_on_com_receive("sfinv_sscsm:formspec_prepend", function(msg) + formspec_prepend = msg +end) + +-- Update player previews. +sscsm.register_on_com_receive("player_api:preview", function() + if blockers == 0 then + minetest.after(0, sfinv.set_player_inventory_formspec) + end +end) diff --git a/files/sfinv_sscsm/depends.txt b/files/sfinv_sscsm/depends.txt new file mode 100644 index 0000000..e354eb3 --- /dev/null +++ b/files/sfinv_sscsm/depends.txt @@ -0,0 +1 @@ +sfinv diff --git a/files/sfinv_sscsm/init.lua b/files/sfinv_sscsm/init.lua new file mode 100644 index 0000000..b2e0ba9 --- /dev/null +++ b/files/sfinv_sscsm/init.lua @@ -0,0 +1,59 @@ +if not minetest.global_exists("sscsm") then + return +end + +-- SSCSM helpers for sfinv +sscsm.register({ + name = "sfinv_sscsm", + file = minetest.get_modpath("sfinv_sscsm") .. DIR_DELIM .. "api.lua", +}) + +-- If an SSCSM handler returns false, it will get sent to the server here. +sscsm.register_on_com_receive("sfinv_sscsm:fields", function(name, fields) + local player = minetest.get_player_by_name(name) + + -- Ensure fields is a table containing only strings. + if type(fields) ~= "table" or not player then return end + for k, v in pairs(fields) do + if type(k) ~= "string" or type(v) ~= "string" then + return + end + end + + -- Run callbacks. + local funcs = minetest.registered_on_player_receive_fields + for i = #funcs, 1, -1 do + if funcs[i](player, "", fields) then + return + end + end +end) + +-- Add sfinv.open_formspec(). +function sfinv.open_formspec(player, context) + local name = player:get_player_name() + if sscsm.has_sscsms_enabled(name) then + sscsm.com_send(name, "sfinv_sscsm:open_formspec") + return + end + local fs = sfinv.get_formspec(player, + context or sfinv.get_or_create_context(player)) + minetest.show_formspec(name, "", fs) +end + +local old_set_page = sfinv.set_page +function sfinv.set_page(player, pagename, temp) + local name = player:get_player_name() + if sscsm.has_sscsms_enabled(name) then + sscsm.com_send(name, "sfinv_sscsm:set_page", {pagename, temp}) + if temp then return end + end + + return old_set_page(player, pagename, temp) +end + +-- Send default.gui_bg and default.listcolors. +sscsm.register_on_sscsms_loaded(function(name) + sscsm.com_send(name, "sfinv_sscsm:formspec_prepend", + default.gui_bg .. default.listcolors) +end) diff --git a/files/sfinv_sscsm/license.txt b/files/sfinv_sscsm/license.txt new file mode 100644 index 0000000..d0b864c --- /dev/null +++ b/files/sfinv_sscsm/license.txt @@ -0,0 +1,25 @@ +License of source code +---------------------- + +The MIT License (MIT) +Copyright (C) 2016-2018 rubenwardy +Copyright (C) 2019-2020 MultiCraft Development Team (MIT) + +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: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +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. + +For more details: +https://opensource.org/licenses/MIT diff --git a/files/sfinv_sscsm/mod.conf b/files/sfinv_sscsm/mod.conf new file mode 100644 index 0000000..b622167 --- /dev/null +++ b/files/sfinv_sscsm/mod.conf @@ -0,0 +1,3 @@ +name = sfinv_sscsm +description = SSCSM port of sfinv +depends = sfinv