Make it possible for mods to handle inv access

i.e. ability to turn off the on_rightclick provided and call the
show_formspec function themselves
This commit is contained in:
cora 2022-09-27 04:59:13 +02:00
parent a3466a1796
commit 29d46d44af
2 changed files with 28 additions and 17 deletions

@ -3,6 +3,9 @@ mcl_entity_invs
Inventories for your entities. It's simple. Depend on mcl_entity_invs and register your entity like so: Inventories for your entities. It's simple. Depend on mcl_entity_invs and register your entity like so:
* mcl_entity_invs.register_inv("entity:name","Title shown in formspec",inventory_size) * mcl_entity_invs.register_inv("entity:name","Title shown in formspec",inventory_size,disable_on_righclick)
*If disable_on_righclick is true other mods can handle when to show the inventory themselves
* mcl_entity_invs.show_inv_form(entity,clicker,"Title shown in formspec")
It works by setting up a detached inventory per entity which is accessed by an id/hash generated from the entities position at creation, the progressed gametime at creation and a random salt. It works by setting up a detached inventory per entity which is accessed by an id/hash generated from the entities position at creation, the progressed gametime at creation and a random salt.

@ -1,5 +1,7 @@
mcl_entity_invs = {} mcl_entity_invs = {}
local open_invs = {}
local function check_distance(inv,player,count) local function check_distance(inv,player,count)
for _,o in pairs(minetest.get_objects_inside_radius(player:get_pos(),5)) do for _,o in pairs(minetest.get_objects_inside_radius(player:get_pos(),5)) do
local l = o:get_luaentity() local l = o:get_luaentity()
@ -39,22 +41,21 @@ local function save_inv(ent)
for i,it in ipairs(ent._inv:get_list("main")) do for i,it in ipairs(ent._inv:get_list("main")) do
ent._items[i] = it:to_string() ent._items[i] = it:to_string()
end end
minetest.remove_detached_inventory(ent._inv_id)
ent._inv = nil
end end
minetest.remove_detached_inventory(ent._inv_id)
end end
local open_invs = {} function mcl_entity_invs.show_inv_form(ent,player,show_name)
local function show_form(ent,player,show_name,size)
if not ent._inv_id then return end if not ent._inv_id then return end
ent._inv = load_inv(ent,size)
if not open_invs[ent] then if not open_invs[ent] then
open_invs[ent] = {} open_invs[ent] = 0
end end
table.insert(open_invs[ent],player:get_player_name()) ent._inv = load_inv(ent,ent._inv_size)
open_invs[ent] = open_invs[ent] + 1
local playername = player:get_player_name() local playername = player:get_player_name()
local rows = 3 local rows = 3
local cols = (math.ceil(size/rows)) local cols = (math.ceil(ent._inv_size/rows))
local spacing = (9 - cols) / 2 local spacing = (9 - cols) / 2
local formspec = "size[9,8.75]" local formspec = "size[9,8.75]"
.. "label[0,0;" .. minetest.formspec_escape( .. "label[0,0;" .. minetest.formspec_escape(
@ -83,7 +84,8 @@ end
minetest.register_on_player_receive_fields(function(player, formname, fields) minetest.register_on_player_receive_fields(function(player, formname, fields)
for k,v in pairs(open_invs) do for k,v in pairs(open_invs) do
if formname == k._inv_id then if formname == k._inv_id then
if #v < 2 then open_invs[k] = open_invs[k] - 1
if open_invs[k] < 1 then
save_inv(k) save_inv(k)
open_invs[k] = nil open_invs[k] = nil
end end
@ -91,8 +93,10 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end end
end) end)
function mcl_entity_invs.register_inv(entity_name,show_name,size) function mcl_entity_invs.register_inv(entity_name,show_name,size,no_on_righclick)
assert(minetest.registered_entities[entity_name],"mcl_entity_invs.register_inv called with invalid entity: "..tostring(entity_name)) assert(minetest.registered_entities[entity_name],"mcl_entity_invs.register_inv called with invalid entity: "..tostring(entity_name))
minetest.registered_entities[entity_name]._inv_size = size
local old_oa = minetest.registered_entities[entity_name].on_activate local old_oa = minetest.registered_entities[entity_name].on_activate
minetest.registered_entities[entity_name].on_activate = function(self,staticdata,dtime_s) minetest.registered_entities[entity_name].on_activate = function(self,staticdata,dtime_s)
local r local r
@ -101,24 +105,28 @@ function mcl_entity_invs.register_inv(entity_name,show_name,size)
if type(d) == "table" and d._inv_id then if type(d) == "table" and d._inv_id then
self._inv_id = d._inv_id self._inv_id = d._inv_id
self._items = d._items self._items = d._items
self._inv_size = d._inv_size
else else
self._inv_id="entity_inv_"..minetest.sha1(minetest.get_gametime()..minetest.pos_to_string(self.object:get_pos())..tostring(math.random())) self._inv_id="entity_inv_"..minetest.sha1(minetest.get_gametime()..minetest.pos_to_string(self.object:get_pos())..tostring(math.random()))
--gametime and position for collision safety and math.random salt to protect against position brute-force --gametime and position for collision safety and math.random salt to protect against position brute-force
end end
return r return r
end end
if not no_on_righclick then
local old_rc = minetest.registered_entities[entity_name].on_rightclick local old_rc = minetest.registered_entities[entity_name].on_rightclick
minetest.registered_entities[entity_name].on_rightclick = function(self,clicker) minetest.registered_entities[entity_name].on_rightclick = function(self,clicker)
show_form(self,clicker,show_name,size) mcl_entity_invs.show_inv_form(self,clicker,show_name)
if old_rc then return old_rc(self,clicker) end if old_rc then return old_rc(self,clicker) end
end
end end
local old_gsd = minetest.registered_entities[entity_name].get_staticdata local old_gsd = minetest.registered_entities[entity_name].get_staticdata
minetest.registered_entities[entity_name].get_staticdata = function(self) minetest.registered_entities[entity_name].get_staticdata = function(self)
local old_sd = old_gsd(self) local old_sd = old_gsd(self)
local d = minetest.deserialize(old_sd) local d = minetest.deserialize(old_sd)
assert(type(d) == "table","mcl_entity_invs currently only works with entities that return a (serialized) table in get_staticdata. "..tostring(self.name).." returned: "..tostring(old_sd)) assert(type(d) == "table","mcl_entity_invs currently only works with entities that return a (serialized) table in get_staticdata. "..tostring(self.name).." returned: "..tostring(old_sd))
d._inv_id = self._inv_id d._inv_id = self._inv_id
d._inv_size = self._inv_size
d._items = {} d._items = {}
if self._items then if self._items then
for i,it in ipairs(self._items) do for i,it in ipairs(self._items) do
@ -130,7 +138,7 @@ function mcl_entity_invs.register_inv(entity_name,show_name,size)
local old_ode = minetest.registered_entities[entity_name].on_deactivate local old_ode = minetest.registered_entities[entity_name].on_deactivate
minetest.registered_entities[entity_name].on_deactivate = function(self,removal) minetest.registered_entities[entity_name].on_deactivate = function(self,removal)
minetest.remove_detached_inventory(self._inv_id) save_inv(self)
if old_ode then return old_ode(self,removal) end if old_ode then return old_ode(self,removal) end
end end