Move node itemstacks from meta inv to field

Node inventories are sent to clients, while metadata
fields are automatically set private by the server
and not sent to clients.  Not using node meta
inventories may help reduce the amount of data
sent to clients, especially in storage-heavy areas
where we were duplicating the work of sending the
inventory data not used on the client, as well as the
visible item entities.

Automatically convert old-format data to new upon
reading.

Also, needed to provide some APIs for sane access
to data in serialized format, and another way to
signal that a node can accept a stack other than
the size of inventory[solo]
This commit is contained in:
Aaron Suen 2021-04-10 09:00:39 -04:00
parent f91bc9d2a1
commit d414c1f3b0
3 changed files with 40 additions and 30 deletions

View File

@ -46,12 +46,29 @@ function nodecore.stack_merge(dest, src)
return src return src
end end
function nodecore.node_inv(pos) local metakey = "ncitem"
return minetest.get_meta(pos):get_inventory()
end
function nodecore.stack_get(pos) function nodecore.stack_get(pos)
return nodecore.node_inv(pos):get_stack("solo", 1) local meta = minetest.get_meta(pos)
local str = meta:get_string(metakey)
if str and str ~= "" then return ItemStack(str) end
local inv = meta:get_inventory()
local stack = inv:get_stack("solo", 1)
if stack:is_empty() then return stack end
meta:set_string(metakey, stack:to_string())
inv:set_size("solo", 0)
return stack
end
function nodecore.stack_get_serial(metatable)
local str = metatable
str = str and str.fields
str = str and str[metakey]
if str and str ~= "" then return ItemStack(str) end
local inv = metatable.inventory
inv = inv and inv.solo
inv = inv and inv[1]
if inv and inv ~= "" then return ItemStack(inv) end
end end
local function update(pos, ...) local function update(pos, ...)
@ -64,12 +81,14 @@ function nodecore.stack_set(pos, stack, player)
nodecore.log("action", string_format("%s sets stack %q at %s", nodecore.log("action", string_format("%s sets stack %q at %s",
player:get_player_name(), shortdesc(stack), minetest.pos_to_string(pos))) player:get_player_name(), shortdesc(stack), minetest.pos_to_string(pos)))
end end
return update(pos, nodecore.node_inv(pos):set_stack("solo", 1, ItemStack(stack))) return update(pos, minetest.get_meta(pos):set_string(metakey,
ItemStack(stack):to_string()))
end end
function nodecore.stack_add(pos, stack, player) function nodecore.stack_add(pos, stack, player)
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
local def = minetest.registered_items[node.name] or {} local def = minetest.registered_items[node.name] or {}
if not def.can_have_itemstack then return end
if def.stack_allow then if def.stack_allow then
local ret = def.stack_allow(pos, node, stack) local ret = def.stack_allow(pos, node, stack)
if ret == false then return stack end if ret == false then return stack end
@ -79,13 +98,8 @@ function nodecore.stack_add(pos, stack, player)
local donate = stack:get_count() local donate = stack:get_count()
local item = nodecore.stack_get(pos) local item = nodecore.stack_get(pos)
local exist = item:get_count() local exist = item:get_count()
local left local left = nodecore.stack_merge(item, stack)
if item:is_empty() then nodecore.stack_set(pos, item)
left = nodecore.node_inv(pos):add_item("solo", stack)
else
left = nodecore.stack_merge(item, stack)
nodecore.stack_set(pos, item)
end
local remain = left:get_count() local remain = left:get_count()
if donate ~= remain then if donate ~= remain then
if player then if player then

View File

@ -148,15 +148,12 @@ nodecore.register_globalstep("visinv check", function()
-- NODE REGISTRATION HELPERS -- NODE REGISTRATION HELPERS
function nodecore.visinv_on_construct(pos) function nodecore.visinv_on_construct(pos)
local meta = minetest.get_meta(pos) return nodecore.visinv_update_ents(pos)
local inv = meta:get_inventory()
inv:set_size("solo", 1)
nodecore.visinv_update_ents(pos)
end end
function nodecore.visinv_after_destruct(pos) function nodecore.visinv_after_destruct(pos)
nodecore.visinv_update_ents(pos) nodecore.visinv_update_ents(pos)
nodecore.fallcheck(pos) return nodecore.fallcheck(pos)
end end
nodecore.register_on_register_item(function(_, def) nodecore.register_on_register_item(function(_, def)
@ -165,6 +162,7 @@ nodecore.register_on_register_item(function(_, def)
def.groups = def.groups or {} def.groups = def.groups or {}
if def.groups.visinv then if def.groups.visinv then
def.can_have_itemstack = true
def.on_construct = def.on_construct or nodecore.visinv_on_construct def.on_construct = def.on_construct or nodecore.visinv_on_construct
def.after_destruct = def.after_destruct or nodecore.visinv_after_destruct def.after_destruct = def.after_destruct or nodecore.visinv_after_destruct
end end

View File

@ -1,21 +1,19 @@
-- LUALOCALS < --------------------------------------------------------- -- LUALOCALS < ---------------------------------------------------------
local ItemStack, minetest, nodecore local minetest, nodecore
= ItemStack, minetest, nodecore = minetest, nodecore
-- LUALOCALS > --------------------------------------------------------- -- LUALOCALS > ---------------------------------------------------------
local modname = minetest.get_current_modname() local modname = minetest.get_current_modname()
nodecore.register_falling_node_on_setnode(function(self, node, meta) nodecore.register_falling_node_on_setnode(function(self, node, meta)
if node and node.name == modname .. ":stack" if not (node and node.name == modname .. ":stack") then return end
and meta and meta.inventory and meta.inventory.solo then local stack = nodecore.stack_get_serial(meta)
local stack = ItemStack(meta.inventory.solo[1] or "") if not stack:is_empty() then
if not stack:is_empty() then local pos = self.object:get_pos()
local pos = self.object:get_pos() if not pos then return end
if not pos then return end local ent = minetest.add_item(pos, stack)
local ent = minetest.add_item(pos, stack) if ent then ent:set_velocity(self.object:get_velocity()) end
if ent then ent:set_velocity(self.object:get_velocity()) end self.object:remove()
self.object:remove() return true
return true
end
end end
end) end)