SmallJoker
2023-01-29 9b7c44b4530bf82790af495ac574a998656cade9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
--[[
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 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
 
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
    end
end)
 
minetest.register_tool("wrench:wrench", {
    description = S("Wrench"),
    inventory_image = "technic_wrench.png",
    tool_capabilities = {
        full_punch_interval = 0.9,
        max_drop_level = 0,
        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}
        },
        damage_groups = {fleshy=1},
    },
    on_place = function(itemstack, placer, pointed_thing)
        local pos = pointed_thing.under
        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
 
        -- 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
            lists[listname] = list
        end
        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,
})