2019-08-25 20:33:44 +02:00
local mod_meta = digtron.mod_meta
-- indexed by digtron_id, set to true whenever the detached inventory's contents change
local dirty_inventories = { }
local detached_inventory_callbacks = {
-- Called when a player wants to move items inside the inventory.
-- Return value: number of items allowed to move.
allow_move = function ( inv , from_list , from_index , to_list , to_index , count , player )
--allow anything in "main"
if to_list == " main " then
return count
end
--only allow fuel items in "fuel"
if to_list == " fuel " then
local stack = inv : get_stack ( from_list , from_index )
if minetest.get_craft_result ( { method = " fuel " , width = 1 , items = { stack } } ) . time ~= 0 then
return count
end
end
return 0
end ,
-- Called when a player wants to put something into the inventory.
-- Return value: number of items allowed to put.
-- Return value -1: Allow and don't modify item count in inventory.
allow_put = function ( inv , listname , index , stack , player )
-- Only allow fuel items to be placed in fuel
if listname == " fuel " then
if minetest.get_craft_result ( { method = " fuel " , width = 1 , items = { stack } } ) . time ~= 0 then
return stack : get_count ( )
else
return 0
end
end
return stack : get_count ( ) -- otherwise, allow all drops
end ,
-- Called when a player wants to take something out of the inventory.
-- Return value: number of items allowed to take.
-- Return value -1: Allow and don't modify item count in inventory.
allow_take = function ( inv , listname , index , stack , player )
return stack : get_count ( )
end ,
-- Called after the actual action has happened, according to what was
-- allowed.
-- No return value.
on_move = function ( inv , from_list , from_index , to_list , to_index , count , player )
dirty_inventories [ inv : get_location ( ) . name ] = true
end ,
on_put = function ( inv , listname , index , stack , player )
dirty_inventories [ inv : get_location ( ) . name ] = true
end ,
on_take = function ( inv , listname , index , stack , player )
dirty_inventories [ inv : get_location ( ) . name ] = true
end ,
}
-- If the detached inventory doesn't exist, reads saved metadata version of the inventory and creates it
-- Doesn't do anything if the detached inventory already exists, the detached inventory is authoritative
local retrieve_inventory = function ( digtron_id )
local inv = minetest.get_inventory ( { type = " detached " , name = digtron_id } )
if inv == nil then
inv = minetest.create_detached_inventory ( digtron_id , detached_inventory_callbacks )
local inv_string = mod_meta : get_string ( digtron_id .. " :inv " )
if inv_string ~= " " then
local inventory_table = minetest.deserialize ( inv_string )
for listname , invlist in pairs ( inventory_table ) do
inv : set_size ( listname , # invlist )
inv : set_list ( listname , invlist )
end
end
end
return inv
end
-- Stores contents of detached inventory as a metadata string
local persist_inventory = function ( digtron_id )
local inv = minetest.get_inventory ( { type = " detached " , name = digtron_id } )
if inv == nil then
minetest.log ( " error " , " [Digtron] persist_inventory attempted to record a nonexistent inventory "
.. digtron_id )
return
end
local lists = inv : get_lists ( )
local persist = { }
for listname , invlist in pairs ( lists ) do
local inventory = { }
for i , stack in ipairs ( invlist ) do
table.insert ( inventory , stack : to_string ( ) ) -- convert into strings for serialization
end
persist [ listname ] = inventory
end
mod_meta : set_string ( digtron_id .. " :inv " , minetest.serialize ( persist ) )
end
minetest.register_globalstep ( function ( dtime )
for digtron_id , _ in pairs ( dirty_inventories ) do
persist_inventory ( digtron_id )
dirty_inventories [ digtron_id ] = nil
end
end )
-- There should only be one of these at a time, but it doesn't cost much to be safe.
local predictive_inventory = { }
-- Copies digtron's inventory into a temporary location so that a dig cycle can be run
-- using it without affecting the actual inventory until everything's been confirmed to work
local get_predictive_inventory = function ( digtron_id )
2019-08-25 23:52:35 +02:00
local existing = predictive_inventory [ digtron_id ]
if existing then return existing end
2019-08-25 20:33:44 +02:00
local predictive_inv = minetest.create_detached_inventory ( " digtron_predictive_ " .. digtron_id , detached_inventory_callbacks )
predictive_inventory [ digtron_id ] = predictive_inv
2019-08-25 23:52:35 +02:00
local source_inv = retrieve_inventory ( digtron_id )
2019-08-25 20:33:44 +02:00
-- Populate predictive inventory with the digtron's contents
2019-08-25 23:52:35 +02:00
for listname , invlist in pairs ( source_inv : get_lists ( ) ) do
predictive_inv : set_size ( listname , # invlist )
predictive_inv : set_list ( listname , invlist )
2019-08-25 20:33:44 +02:00
end
return predictive_inv
end
2019-08-25 23:52:35 +02:00
-- Wipes predictive inventory without committing it (eg, on failure of predicted operation)
local clear_predictive_inventory = function ( digtron_id )
2019-08-25 20:33:44 +02:00
local predictive_inv = predictive_inventory [ digtron_id ]
if not predictive_inv then
2019-08-25 23:52:35 +02:00
minetest.log ( " error " , " [Digtron] clear_predictive_inventory called for " .. digtron_id
2019-08-25 20:33:44 +02:00
.. " but predictive inventory did not exist " )
return
end
minetest.remove_detached_inventory ( " digtron_predictive_ " .. digtron_id )
predictive_inventory [ digtron_id ] = nil
2019-08-26 01:16:23 +02:00
if next ( predictive_inventory ) ~= nil then
2019-08-25 20:33:44 +02:00
minetest.log ( " warning " , " [Digtron] multiple predictive inventories were in existence, this shouldn't be happening. File an issue with Digtron programmers. " )
end
end
2019-08-25 23:52:35 +02:00
-- Copies the predictive inventory's contents into the actual digtron's inventory and wipes the predictive inventory
local commit_predictive_inventory = function ( digtron_id )
2019-08-25 20:33:44 +02:00
local predictive_inv = predictive_inventory [ digtron_id ]
if not predictive_inv then
2019-08-25 23:52:35 +02:00
minetest.log ( " error " , " [Digtron] commit_predictive_inventory called for " .. digtron_id
2019-08-25 20:33:44 +02:00
.. " but predictive inventory did not exist " )
return
end
2019-08-25 23:52:35 +02:00
local source_inv = retrieve_inventory ( digtron_id )
for listname , invlist in pairs ( predictive_inv : get_lists ( ) ) do
source_inv : set_list ( listname , invlist )
2019-08-25 20:33:44 +02:00
end
2019-08-25 23:52:35 +02:00
dirty_inventories [ digtron_id ] = true
clear_predictive_inventory ( digtron_id )
2019-08-25 20:33:44 +02:00
end
return {
retrieve_inventory = retrieve_inventory ,
persist_inventory = persist_inventory ,
get_predictive_inventory = get_predictive_inventory ,
commit_predictive_inventory = commit_predictive_inventory ,
clear_predictive_inventory = clear_predictive_inventory ,
}