2017-07-06 14:02:17 +02:00

206 lines
6.1 KiB
Lua

woodcutting = {}
woodcutting.tree_content_ids = {}
woodcutting.leaves_content_ids = {}
woodcutting.inprocess = {}
-----------------------------
-- Process single node async
----------------------------
local function woodcut_node(pos, playername)
-- check digger is still in game
local digger = minetest.get_player_by_name(playername)
if not digger then
woodcutting.inprocess[playername] = nil
return
end
-- check node already digged / right node at place
local node = minetest.get_node(pos)
local id = minetest.get_content_id(node.name)
if not (woodcutting.tree_content_ids[id] or woodcutting.leaves_content_ids[id]) then
return
end
-- dig the node
minetest.node_dig(pos, node, digger)
-- Search for leaves only for tree
if not woodcutting.tree_content_ids[id] then
return
end
-- read map around the node
local vm = minetest.get_voxel_manip()
local minp, maxp = vm:read_from_map(vector.subtract(pos, 8), vector.add(pos, 8))
local area = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
local data = vm:get_data()
-- process leaves nodes
for i in area:iterp(vector.subtract(pos,8), vector.add(pos,8)) do
if woodcutting.leaves_content_ids[data[i]] then
local leavespos = area:position(i)
-- search if no other tree node near the leaves
local tree_found = false
for i2 in area:iterp(vector.subtract(leavespos,2), vector.add(leavespos,2)) do
if woodcutting.tree_content_ids[data[i2] ] then
-- local chkposhash = minetest.hash_node_position(area:position(i2))
-- if not process.treenodes_hashed[chkposhash] and
tree_found = true
break
-- end
end
end
if not tree_found then
minetest.after(0.1, woodcut_node, leavespos, playername)
end
end
end
end
----------------------------
-- Process all relevant nodes around the digged
----------------------------
local function woodcut(playername)
-- check digger is still in game
local digger = minetest.get_player_by_name(playername)
if not digger then
woodcutting.inprocess[playername] = nil
return
end
local playerpos = digger:get_pos()
-- check the process
local process = woodcutting.inprocess[playername]
if not process then
return
end
-- sort the table for priorization higher nodes, select the first one and process them
table.sort(process.treenodes_sorted, function(a,b)
local aval = math.abs(playerpos.x-a.x) + math.abs(playerpos.z-a.z)
local bval = math.abs(playerpos.x-b.x) + math.abs(playerpos.z-b.z)
if aval == bval then -- if same horizontal distance, prever higher node
aval = -a.z
bval = -b.z
end
return aval < bval
end)
local pos = process.treenodes_sorted[1]
if pos then
local poshash = minetest.hash_node_position(pos)
local nodedef = minetest.registered_nodes[process.treenodes_hashed[poshash]]
local capabilities = digger:get_wielded_item():get_tool_capabilities()
local dig_params = minetest.get_dig_params(nodedef.groups, capabilities)
table.remove(process.treenodes_sorted, 1)
process.treenodes_hashed[poshash] = nil
minetest.after(0.0, woodcut_node, pos, playername)
-- next step
minetest.after(dig_params.time, woodcut, playername)
else
-- finished
digger:hud_remove(woodcutting.inprocess[playername].hud)
woodcutting.inprocess[playername] = nil
end
end
----------------------------
-- dig node - check if woodcutting and initialize the work
----------------------------
minetest.register_on_dignode(function(pos, oldnode, digger)
-- check removed node is tree / check the digger is still online
local id = minetest.get_content_id(oldnode.name)
if not woodcutting.tree_content_ids[id] or not digger then
return
end
-- Check if it is an in process job
local playername = digger:get_player_name()
local sneak = digger:get_player_control().sneak
local process
if woodcutting.inprocess[playername] then
-- woodcutting job already in process
process = woodcutting.inprocess[playername]
elseif not sneak then
-- No job, no sneak, nothing to do
return
else
-- No job but sneak pressed - start new process
process = {
sneak_pressed = true,
treenodes_sorted = {}, -- simple sortable list
treenodes_hashed = {}, -- With minetest.hash_node_position(9 as key for deduplication
}
process.hud = digger:hud_add({
hud_elem_type = "text",
position = {x=0.3,y=0.3},
alignment = {x=0,y=0},
size = "",
text = "Woodcutting active. Hold sneak key to disable it",
number = 0xFFFFFF,
offset = {x=0, y=0},
})
woodcutting.inprocess[playername] = process
minetest.after(0.1, woodcut, playername) -- note: woodcut is called after the treenodes_lists are filled
end
-- process the sneak toggle
if sneak then
if not process.sneak_pressed then
-- sneak pressed second time - stop the work
digger:hud_remove(woodcutting.inprocess[playername].hud)
woodcutting.inprocess[playername] = nil
return
end
else
if process.sneak_pressed then
process.sneak_pressed = false
end
end
-- read map around the node
local vm = minetest.get_voxel_manip()
local minp, maxp = vm:read_from_map(vector.subtract(pos, 1), vector.add(pos, 1))
local area = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
local data = vm:get_data()
-- collect tree nodes to the lists
for i in area:iterp(vector.subtract(pos,1), vector.add(pos,1)) do
local tree_nodename = woodcutting.tree_content_ids[data[i]]
if tree_nodename then
local pos = area:position(i)
local poshash = minetest.hash_node_position(pos)
if not process.treenodes_hashed[poshash] then
table.insert(process.treenodes_sorted, pos)
process.treenodes_hashed[poshash] = tree_nodename
end
end
end
end)
-- start collecting infos about trees and leaves after all mods loaded
minetest.after(0, function ()
for k, v in pairs(minetest.registered_nodes) do
if v.groups.tree then
local id = minetest.get_content_id(k)
woodcutting.tree_content_ids[id] = k
elseif v.groups.leafdecay then
local id = minetest.get_content_id(k)
woodcutting.leaves_content_ids[id] = k
end
end
end)
minetest.register_on_dieplayer(function(player)
local playername = player:get_player_name()
if woodcutting.inprocess[playername] then
player:hud_remove(woodcutting.inprocess[playername].hud)
woodcutting.inprocess[playername] = nil
end
end)