|
| 1 | + |
| 2 | +local S = rawget(_G, "intllib") and intllib.Getter() or function(s) return s end |
| 3 | + |
| 4 | +local SERIALIZATION_VERSION = 1 |
| 5 | + |
| 6 | +local errors = { |
| 7 | + owned = S("Cannot pickup node. Owned by %s."), |
| 8 | + full_inv = S("Not enough room in inventory to pickup node."), |
| 9 | + bad_item = S("Cannot pickup node containing %s."), |
| 10 | + nested = S("Cannot pickup node. Nesting inventories is not allowed."), |
| 11 | + metadata = S("Cannot pickup node. Node contains too much metadata."), |
| 12 | +} |
| 13 | + |
| 14 | +local function get_stored_metadata(itemstack) |
| 15 | + local meta = itemstack:get_meta() |
| 16 | + local data = meta:get("data") or meta:get("") |
| 17 | + data = minetest.deserialize(data) |
| 18 | + if not data or not data.version or not data.name then |
| 19 | + return |
| 20 | + end |
| 21 | + return data |
| 22 | +end |
| 23 | + |
| 24 | +local function get_description(def, pos, meta, node, player) |
| 25 | + local t = type(def.description) |
| 26 | + if t == "string" then |
| 27 | + return def.description |
| 28 | + elseif t == "function" then |
| 29 | + local desc = def.description(pos, meta, node, player) |
| 30 | + if desc then |
| 31 | + return desc |
| 32 | + end |
| 33 | + end |
| 34 | + return S("%s with items"):format(minetest.registered_nodes[node.name].description) |
| 35 | +end |
| 36 | + |
| 37 | +function wrench.pickup_node(pos, player) |
| 38 | + local node = minetest.get_node(pos) |
| 39 | + local def = wrench.registered_nodes[node.name] |
| 40 | + if not def then |
| 41 | + return |
| 42 | + end |
| 43 | + local meta = minetest.get_meta(pos) |
| 44 | + if def.owned and not minetest.check_player_privs(player, "protection_bypass") then |
| 45 | + local owner = meta:get_string("owner") |
| 46 | + if owner ~= "" and owner ~= player:get_player_name() then |
| 47 | + return false, errors.owned:format(owner) |
| 48 | + end |
| 49 | + end |
| 50 | + local data = { |
| 51 | + name = node.name, |
| 52 | + version = SERIALIZATION_VERSION, |
| 53 | + lists = {}, |
| 54 | + metas = {}, |
| 55 | + } |
| 56 | + local inv = meta:get_inventory() |
| 57 | + for _, listname in pairs(def.lists or {}) do |
| 58 | + local list = inv:get_list(listname) |
| 59 | + for i, stack in pairs(list) do |
| 60 | + if wrench.blacklisted_items[stack:get_name()] then |
| 61 | + local desc = stack:get_definition().description |
| 62 | + return false, errors.bad_item:format(desc) |
| 63 | + end |
| 64 | + local sdata = get_stored_metadata(stack) |
| 65 | + if sdata and sdata.lists and next(sdata.lists) ~= nil then |
| 66 | + return false, errors.nested |
| 67 | + end |
| 68 | + list[i] = stack:to_string() |
| 69 | + end |
| 70 | + data.lists[listname] = list |
| 71 | + end |
| 72 | + for name, meta_type in pairs(def.metas or {}) do |
| 73 | + if meta_type == wrench.META_TYPE_FLOAT then |
| 74 | + data.metas[name] = meta:get_float(name) |
| 75 | + elseif meta_type == wrench.META_TYPE_STRING then |
| 76 | + data.metas[name] = meta:get_string(name) |
| 77 | + elseif meta_type == wrench.META_TYPE_INT then |
| 78 | + data.metas[name] = meta:get_int(name) |
| 79 | + end |
| 80 | + end |
| 81 | + local stack = ItemStack(node.name) |
| 82 | + local item_meta = stack:get_meta() |
| 83 | + item_meta:set_string("data", minetest.serialize(data)) |
| 84 | + item_meta:set_string("description", get_description(def, pos, meta, node, player)) |
| 85 | + if #stack:to_string() > 65000 then |
| 86 | + return false, errors.metadata |
| 87 | + end |
| 88 | + local player_inv = player:get_inventory() |
| 89 | + if not player_inv:room_for_item("main", stack) then |
| 90 | + return false, errors.full_inv |
| 91 | + end |
| 92 | + player_inv:add_item("main", stack) |
| 93 | + minetest.remove_node(pos) |
| 94 | + return true |
| 95 | +end |
| 96 | + |
| 97 | +function wrench.restore_node(pos, player, stack) |
| 98 | + if not stack then |
| 99 | + return |
| 100 | + end |
| 101 | + local data = get_stored_metadata(stack) |
| 102 | + if not data then |
| 103 | + return |
| 104 | + end |
| 105 | + local def = wrench.registered_nodes[data.name] |
| 106 | + if not def then |
| 107 | + return |
| 108 | + end |
| 109 | + local meta = minetest.get_meta(pos) |
| 110 | + local inv = meta:get_inventory() |
| 111 | + for listname, list in pairs(data.lists) do |
| 112 | + inv:set_list(listname, list) |
| 113 | + end |
| 114 | + for name, value in pairs(data.metas) do |
| 115 | + local meta_type = def.metas and def.metas[name] |
| 116 | + if meta_type == wrench.META_TYPE_INT then |
| 117 | + meta:set_int(name, value) |
| 118 | + elseif meta_type == wrench.META_TYPE_FLOAT then |
| 119 | + meta:set_float(name, value) |
| 120 | + elseif meta_type == wrench.META_TYPE_STRING then |
| 121 | + meta:set_string(name, value) |
| 122 | + end |
| 123 | + end |
| 124 | + if def.after_place then |
| 125 | + def.after_place(pos, player, stack) |
| 126 | + end |
| 127 | + return true |
| 128 | +end |
0 commit comments