SmallJoker
2023-01-29 9b7c44b4530bf82790af495ac574a998656cade9
wrench/init.lua
@@ -1,91 +1,97 @@
local supported_nodes = {
["default:chest"] = {name="wrench:default_chest", lists={"main"}},
["default:furnace"] = {name="wrench:default_furnace", lists={"fuel", "src", "dst"}},
["default:furnace_active"] = {name="wrench:default_furnace", lists={"fuel", "src", "dst"}},
["technic:iron_chest"] = {name="wrench:technic_iron_chest", lists={"main"}},
["technic:iron_locked_chest"] = {name="wrench:technic_iron_locked_chest", lists={"main"}},
["technic:copper_chest"] = {name="wrench:technic_copper_chest", lists={"main"}},
["technic:copper_locked_chest"] = {name="wrench:technic_copper_locked_chest", lists={"main"}},
["technic:silver_chest"] = {name="wrench:technic_silver_chest", lists={"main"}},
["technic:silver_locked_chest"] = {name="wrench:technic_silver_locked_chest", lists={"main"}},
["technic:gold_chest"] = {name="wrench:technic_gold_chest", lists={"main"}},
["technic:gold_locked_chest"] = {name="wrench:technic_gold_locked_chest", lists={"main"}},
["technic:mithril_chest"] = {name="wrench:technic_mithril_chest", lists={"main"}},
["technic:mithril_locked_chest"] = {name="wrench:technic_mithril_locked_chest", lists={"main"}},
["technic:electric_furnace"] = {name="wrench:technic_electric_furnace", lists={"src", "dst"}},
["technic:electric_furnace_active"] = {name="wrench:technic_electric_furnace_active", lists={"src", "dst"}},
["technic:mv_electric_furnace"] = {name="wrench:technic_mv_electric_furnace", lists={"src", "dst", "upgrade1", "upgrade2"}},
["technic:mv_electric_furnace_active"] = {name="wrench:technic_mv_electric_furnace_active", lists={"src", "dst", "upgrade1", "upgrade2"}},
["technic:coal_alloy_furnace"] = {name="wrench:technic_coal_alloy_furnace", lists={"fuel", "src", "src2", "dst"}},
["technic:coal_alloy_furnace_active"] = {name="wrench:technic_coal_alloy_furnace_active", lists={"fuel", "src", "src2", "dst"}},
["technic:alloy_furnace"] = {name="wrench:technic_alloy_furnace", lists={"src", "src2", "dst"}},
["technic:alloy_furnace_active"] = {name="wrench:technic_alloy_furnace_active", lists={"src", "src2", "dst"}},
["technic:mv_alloy_furnace"] = {name="wrench:technic_mv_alloy_furnace", lists={"src", "src2", "dst", "upgrade1", "upgrade2"}},
["technic:mv_alloy_furnace_active"] = {name="wrench:technic_mv_alloy_furnace_active", lists={"src", "src2", "dst", "upgrade1", "upgrade2"}},
["technic:grinder"] = {name="wrench:technic_grinder", lists={"src", "dst"}},
["technic:grinder_active"] = {name="wrench:technic_grinder_active", lists={"src", "dst"}},
}
local chest_mark_colors = {
    {'_black','Black'},
    {'_blue','Blue'},
    {'_brown','Brown'},
    {'_cyan','Cyan'},
    {'_dark_green','Dark Green'},
    {'_dark_grey','Dark Grey'},
    {'_green','Green'},
    {'_grey','Grey'},
    {'_magenta','Magenta'},
    {'_orange','Orange'},
    {'_pink','Pink'},
    {'_red','Red'},
    {'_violet','Violet'},
    {'_white','White'},
    {'_yellow','Yellow'},
    {'','None'}
}
for i=1,15,1 do
   supported_nodes["technic:gold_chest"..chest_mark_colors[i][1]] = {name="wrench:technic_gold_chest"..chest_mark_colors[i][1], lists={"main"}}
   supported_nodes["technic:gold_locked_chest"..chest_mark_colors[i][1]] = {name="wrench:technic_gold_locked_chest"..chest_mark_colors[i][1], lists={"main"}}
--[[
Wrench mod
Adds a wrench that allows the player to pickup nodes that contain an inventory
with items or metadata that needs perserving.
The wrench has the same tool capability as the normal hand.
To pickup a node simply right click on it. If the node contains a formspec,
you will need to shift+right click instead.
Because it enables arbitrary nesting of chests, and so allows the player
to carry an unlimited amount of material at once, this wrench is not
available to survival-mode players.
--]]
local LATEST_SERIALIZATION_VERSION = 1
wrench = {}
local modpath = minetest.get_modpath(minetest.get_current_modname())
dofile(modpath.."/support.lua")
dofile(modpath.."/technic.lua")
-- Boilerplate to support localized strings if intllib mod is installed.
local S = rawget(_G, "intllib") and intllib.Getter() or function(s) return s end
local function get_meta_type(name, metaname)
   local def = wrench.registered_nodes[name]
   return def and def.metas and def.metas[metaname] or nil
end
local function convert_to_original_name(name)
   for key,value in pairs(supported_nodes) do
      if name == value.name then return key end
local function get_pickup_name(name)
   return "wrench:picked_up_"..(name:gsub(":", "_"))
end
local function restore(pos, placer, itemstack)
   local data = itemstack:get_meta():get_string("data")
   data = (data ~= "" and data) or   itemstack:get_metadata()
   data = minetest.deserialize(data)
   if not data then
      minetest.remove_node(pos)
      minetest.log("error", placer:get_player_name().." wanted to place "..
            itemstack:get_name().." at "..minetest.pos_to_string(pos)..
            ", but it had no data.")
      minetest.log("verbose", "itemstack: "..itemstack:to_string())
      return true
   end
   local node = minetest.get_node(pos)
   minetest.set_node(pos, {name = data.name, param2 = node.param2})
   -- Apply stored metadata to the current node
   local meta = minetest.get_meta(pos)
   local inv = meta:get_inventory()
   for key, value in pairs(data.metas) do
      local meta_type = get_meta_type(data.name, key)
      if meta_type == wrench.META_TYPE_INT then
         meta:set_int(key, value)
      elseif meta_type == wrench.META_TYPE_FLOAT then
         meta:set_float(key, value)
      elseif meta_type == wrench.META_TYPE_STRING then
         meta:set_string(key, value)
      end
   end
   for listname, list in pairs(data.lists) do
      inv:set_list(listname, list)
   end
   itemstack:take_item()
   return itemstack
end
for name,_ in pairs(supported_nodes) do
   local olddef = minetest.registered_nodes[name]
   if olddef ~= nil then
      local newdef = {}
      for key,value in pairs(olddef) do
         newdef[key] = value
      end
      name = supported_nodes[name].name
      newdef.stack_max = 1
      newdef.description = newdef.description.." with items"
      newdef.groups.not_in_creative_inventory = 1
      newdef.on_construct = nil
      newdef.on_destruct = nil
      newdef.after_place_node = function(pos, placer, itemstack)
         if olddef.after_place_node ~= nil then olddef.after_place_node(pos, placer, itemstack) end
         if not placer:is_player() then return end
         local node = minetest.get_node(pos)
         local item = convert_to_original_name(itemstack:get_name())
         minetest.set_node(pos, {name = item, param2 = node.param2})
         local inv = minetest.get_meta(pos):get_inventory()
         local data = minetest.deserialize(itemstack:get_metadata())
         for listname,list in pairs(data) do
            inv:set_list(listname, list)
minetest.register_on_mods_loaded(function()
   -- Delayed registration for foreign mod support
   for name, info in pairs(wrench.registered_nodes) do
      local olddef = minetest.registered_nodes[name]
      if olddef then
         local newdef = {}
         for key, value in pairs(olddef) do
            newdef[key] = value
         end
         newdef.stack_max = 1
         newdef.description = S("%s with items"):format(newdef.description)
         newdef.groups = {}
         newdef.groups.not_in_creative_inventory = 1
         newdef.on_construct = nil
         newdef.on_destruct = nil
         newdef.after_place_node = restore
         minetest.register_node(":"..get_pickup_name(name), newdef)
      end
      minetest.register_node(name, newdef)
   end
end
end)
minetest.register_tool("wrench:wrench", {
   description = "Wrench",
   description = S("Wrench"),
   inventory_image = "technic_wrench.png",
   tool_capabilities = {
      full_punch_interval = 0.9,
@@ -93,62 +99,78 @@
      groupcaps = {
         crumbly = {times={[2]=3.00, [3]=0.70}, uses=0, maxlevel=1},
         snappy = {times={[3]=0.40}, uses=0, maxlevel=1},
         oddly_breakable_by_hand = {times={[1]=7.00,[2]=4.00,[3]=1.40}, uses=0, maxlevel=3}
         oddly_breakable_by_hand = {times={[1]=7.00,[2]=4.00,[3]=1.40},
                  uses=0, maxlevel=3}
      },
      damage_groups = {fleshy=1},
   },
   on_place = function(itemstack, placer, pointed_thing)
      if not placer:is_player() then return end
      local pos = pointed_thing.under
      if pos == nil then return end
      local name = minetest.get_node(pos).name
      local support = supported_nodes[name]
      if support == nil then return end
      if name:find("_locked_chest") ~= nil then
         local meta = minetest.get_meta(pos)
         if not has_locked_chest_privilege(meta, placer) then
            minetest.log("action", player:get_player_name()..
            " tried to destroy a locked chest belonging to "..
            meta:get_string("owner").." at "..
            minetest.pos_to_string(pos))
      if not placer or not pos then
         return
      end
      local player_name = placer:get_player_name()
      if minetest.is_protected(pos, player_name) then
         minetest.record_protection_violation(pos, player_name)
         return
      end
      local node_name = minetest.get_node(pos).name
      local def = wrench.registered_nodes[node_name]
      if not def then
         return
      end
      local stack_pickup = ItemStack(get_pickup_name(node_name))
      local player_inv = placer:get_inventory()
      if not player_inv:room_for_item("main", stack_pickup) then
         return
      end
      local meta = minetest.get_meta(pos)
      if def.owned and not minetest.check_player_privs(placer, "protection_bypass") then
         local owner = meta:get_string("owner")
         if owner and owner ~= player_name then
            minetest.log("action", player_name..
               " tried to pick up an owned node belonging to "..
               owner.." at "..
               minetest.pos_to_string(pos))
            return
         end
      end
      local lists = support.lists
      local inv = minetest.get_meta(pos):get_inventory()
      local empty = true
      local list_str = {}
      for i=1,#lists,1 do
         if not inv:is_empty(lists[i]) then empty = false end
         local list = inv:get_list(lists[i])
         for j=1,#list,1 do
            list[j] = list[j]:to_string()
      -- Do the actual pickup:
      local metadata = {}
      metadata.name = node_name
      metadata.version = LATEST_SERIALIZATION_VERSION
      -- Serialize inventory lists + items
      local inv = meta:get_inventory()
      local lists = {}
      for _, listname in pairs(def.lists or {}) do
         local list = inv:get_list(listname)
         for i, stack in pairs(list) do
            list[i] = stack:to_string()
         end
         list_str[lists[i]] = list
         lists[listname] = list
      end
      inv = placer:get_inventory()
      local stack = {}
      stack.name = name
      if inv:room_for_item("main", stack) then
         minetest.remove_node(pos)
         itemstack:add_wear(65535/20)
         if empty then
            inv:add_item("main", stack)
         else
            stack.name = supported_nodes[name].name
            stack.metadata = minetest.serialize(list_str)
            inv:add_item("main", stack)
      metadata.lists = lists
      -- Serialize node metadata fields
      local item_meta = stack_pickup:get_meta()
      metadata.metas = {}
      for key, meta_type in pairs(def.metas or {}) do
         if meta_type == wrench.META_TYPE_INT then
            metadata.metas[key] = meta:get_int(key)
         elseif meta_type == wrench.META_TYPE_FLOAT then
            metadata.metas[key] = meta:get_float(key)
         elseif meta_type == wrench.META_TYPE_STRING then
            metadata.metas[key] = meta:get_string(key)
         end
      end
      item_meta:set_string("data", minetest.serialize(metadata))
      minetest.remove_node(pos)
      itemstack:add_wear(65535 / 20)
      player_inv:add_item("main", stack_pickup)
      return itemstack
   end,
})
minetest.register_craft({
   output = "wrench:wrench",
   recipe = {
   {"default:iron_lump","","default:iron_lump"},
   {"","default:iron_lump",""},
   {"","default:iron_lump",""},
   },
})