mirror of
https://github.com/minetest-mods/digtron.git
synced 2024-10-04 00:23:07 +02:00
no need to persist derived values. Cache digger targets.
This commit is contained in:
parent
63ea1314ab
commit
a0f47b50bc
@ -144,14 +144,14 @@ minetest.register_node("digtron:controller", {
|
|||||||
local success, succeeded, failed = digtron.is_buildable_to(digtron_id, target_pos, player_name)
|
local success, succeeded, failed = digtron.is_buildable_to(digtron_id, target_pos, player_name)
|
||||||
if success then
|
if success then
|
||||||
digtron.build_to_world(digtron_id, target_pos, player_name)
|
digtron.build_to_world(digtron_id, target_pos, player_name)
|
||||||
minetest.sound_play("digtron_machine_assemble", {gain = 0.5, pos=root_pos})
|
minetest.sound_play("digtron_machine_assemble", {gain = 0.5, pos=target_pos})
|
||||||
-- Note: DO NOT RESPECT CREATIVE MODE here.
|
-- Note: DO NOT RESPECT CREATIVE MODE here.
|
||||||
-- If we allow multiple copies of a Digtron running around with the same digtron_id,
|
-- If we allow multiple copies of a Digtron running around with the same digtron_id,
|
||||||
-- human sacrifice, dogs and cats living together, mass hysteria!
|
-- human sacrifice, dogs and cats living together, mass hysteria
|
||||||
return ItemStack("")
|
return ItemStack("")
|
||||||
else
|
else
|
||||||
digtron.show_buildable_nodes(succeeded, failed)
|
digtron.show_buildable_nodes(succeeded, failed)
|
||||||
minetest.sound_play("digtron_buzzer", {gain = 0.5, pos=root_pos})
|
minetest.sound_play("digtron_buzzer", {gain = 0.5, pos=target_pos})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return itemstack
|
return itemstack
|
||||||
|
168
functions.lua
168
functions.lua
@ -197,8 +197,6 @@ local get_table_functions = function(identifier)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local persist_layout, retrieve_layout = get_table_functions("layout")
|
local persist_layout, retrieve_layout = get_table_functions("layout")
|
||||||
local persist_adjacent, retrieve_adjacent = get_table_functions("adjacent")
|
|
||||||
local persist_bounding_box, retrieve_bounding_box = get_table_functions("bounding_box")
|
|
||||||
local persist_pos, retrieve_pos, dispose_pos = get_table_functions("pos")
|
local persist_pos, retrieve_pos, dispose_pos = get_table_functions("pos")
|
||||||
|
|
||||||
digtron.get_pos = retrieve_pos
|
digtron.get_pos = retrieve_pos
|
||||||
@ -206,28 +204,39 @@ digtron.get_pos = retrieve_pos
|
|||||||
-------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------
|
||||||
-- Layout creation helpers
|
-- Layout creation helpers
|
||||||
|
|
||||||
local cardinal_directions = {
|
local cardinal_dirs = {
|
||||||
{x=1,y=0,z=0},
|
{x= 0, y=0, z= 1},
|
||||||
{x=-1,y=0,z=0},
|
{x= 1, y=0, z= 0},
|
||||||
{x=0,y=1,z=0},
|
{x= 0, y=0, z=-1},
|
||||||
{x=0,y=-1,z=0},
|
{x=-1, y=0, z= 0},
|
||||||
{x=0,y=0,z=1},
|
{x= 0, y=-1, z= 0},
|
||||||
{x=0,y=0,z=-1},
|
{x= 0, y=1, z= 0},
|
||||||
|
}
|
||||||
|
-- Mapping from facedir value to index in cardinal_dirs.
|
||||||
|
local facedir_to_dir_map = {
|
||||||
|
[0]=1, 2, 3, 4,
|
||||||
|
5, 2, 6, 4,
|
||||||
|
6, 2, 5, 4,
|
||||||
|
1, 5, 3, 6,
|
||||||
|
1, 6, 3, 5,
|
||||||
|
1, 4, 3, 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
local update_bounding_box = function(bounding_box, pos)
|
-- Turn the cardinal directions into a set of integers you can add to a hash to step in that direction.
|
||||||
bounding_box.minp.x = math.min(bounding_box.minp.x, pos.x)
|
local cardinal_dirs_hash = {}
|
||||||
bounding_box.minp.y = math.min(bounding_box.minp.y, pos.y)
|
for i, dir in ipairs(cardinal_dirs) do
|
||||||
bounding_box.minp.z = math.min(bounding_box.minp.z, pos.z)
|
cardinal_dirs_hash[i] = minetest.hash_node_position(dir) - minetest.hash_node_position({x=0, y=0, z=0})
|
||||||
bounding_box.maxp.x = math.max(bounding_box.maxp.x, pos.x)
|
end
|
||||||
bounding_box.maxp.y = math.max(bounding_box.maxp.y, pos.y)
|
|
||||||
bounding_box.maxp.z = math.max(bounding_box.maxp.z, pos.z)
|
-- Given a facedir, returns an index into either cardinal_dirs or cardinal_dirs_hash that
|
||||||
|
local facedir_to_dir_index = function(param2)
|
||||||
|
return facedir_to_dir_map[param2 % 32]
|
||||||
end
|
end
|
||||||
|
|
||||||
-- recursive function searches out all connected unassigned digtron nodes
|
-- recursive function searches out all connected unassigned digtron nodes
|
||||||
local get_all_adjacent_digtron_nodes
|
local get_all_digtron_nodes
|
||||||
get_all_adjacent_digtron_nodes = function(pos, digtron_nodes, digtron_adjacent, bounding_box, player_name)
|
get_all_digtron_nodes = function(pos, digtron_nodes, digtron_adjacent, player_name)
|
||||||
for _, dir in ipairs(cardinal_directions) do
|
for _, dir in ipairs(cardinal_dirs) do
|
||||||
local test_pos = vector.add(pos, dir)
|
local test_pos = vector.add(pos, dir)
|
||||||
local test_hash = minetest.hash_node_position(test_pos)
|
local test_hash = minetest.hash_node_position(test_pos)
|
||||||
if not (digtron_nodes[test_hash] or digtron_adjacent[test_hash]) then -- don't test twice
|
if not (digtron_nodes[test_hash] or digtron_adjacent[test_hash]) then -- don't test twice
|
||||||
@ -242,8 +251,7 @@ get_all_adjacent_digtron_nodes = function(pos, digtron_nodes, digtron_adjacent,
|
|||||||
else
|
else
|
||||||
--test_node.group_value = group_value -- for later ease of reference
|
--test_node.group_value = group_value -- for later ease of reference
|
||||||
digtron_nodes[test_hash] = test_node
|
digtron_nodes[test_hash] = test_node
|
||||||
update_bounding_box(bounding_box, test_pos)
|
get_all_digtron_nodes(test_pos, digtron_nodes, digtron_adjacent, player_name) -- recurse
|
||||||
get_all_adjacent_digtron_nodes(test_pos, digtron_nodes, digtron_adjacent, bounding_box, player_name) -- recurse
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- don't record details, the content of this node will change as the digtron moves
|
-- don't record details, the content of this node will change as the digtron moves
|
||||||
@ -253,6 +261,82 @@ get_all_adjacent_digtron_nodes = function(pos, digtron_nodes, digtron_adjacent,
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------
|
||||||
|
-- Cache-only data, not persisted
|
||||||
|
|
||||||
|
cache_bounding_box = {}
|
||||||
|
local update_bounding_box = function(bounding_box, pos)
|
||||||
|
bounding_box.minp.x = math.min(bounding_box.minp.x, pos.x)
|
||||||
|
bounding_box.minp.y = math.min(bounding_box.minp.y, pos.y)
|
||||||
|
bounding_box.minp.z = math.min(bounding_box.minp.z, pos.z)
|
||||||
|
bounding_box.maxp.x = math.max(bounding_box.maxp.x, pos.x)
|
||||||
|
bounding_box.maxp.y = math.max(bounding_box.maxp.y, pos.y)
|
||||||
|
bounding_box.maxp.z = math.max(bounding_box.maxp.z, pos.z)
|
||||||
|
end
|
||||||
|
local retrieve_bounding_box = function(digtron_id)
|
||||||
|
local val = cache_bounding_box[digtron_id]
|
||||||
|
if val then return val end
|
||||||
|
|
||||||
|
local layout = retrieve_layout(digtron_id)
|
||||||
|
if layout == nil then return nil end
|
||||||
|
|
||||||
|
local bbox = {minp = {x=0, y=0, z=0}, maxp = {x=0, y=0, z=0}}
|
||||||
|
for hash, data in pairs(layout) do
|
||||||
|
update_bounding_box(bbox, minetest.get_position_from_hash(hash))
|
||||||
|
end
|
||||||
|
cache_bounding_box[digtron_id] = bbox
|
||||||
|
return bbox
|
||||||
|
end
|
||||||
|
|
||||||
|
cache_all_adjacent_pos = {}
|
||||||
|
cache_all_digger_targets = {}
|
||||||
|
local refresh_adjacent = function(digtron_id)
|
||||||
|
local layout = retrieve_layout(digtron_id)
|
||||||
|
if layout == nil then return nil end
|
||||||
|
|
||||||
|
local adjacent = {}
|
||||||
|
local adjacent_to_diggers = {}
|
||||||
|
for hash, data in pairs(layout) do
|
||||||
|
for _, dir_hash in ipairs(cardinal_dirs_hash) do
|
||||||
|
local potential_adjacent = hash+dir_hash
|
||||||
|
if layout[potential_adjacent] == nil then
|
||||||
|
adjacent[potential_adjacent] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if minetest.get_item_group(data.node.name, "digtron") == 3 then
|
||||||
|
local potential_target = hash + cardinal_dirs_hash[facedir_to_dir_index(data.node.param2)]
|
||||||
|
if layout[potential_target] == nil then
|
||||||
|
local fields = data.meta.fields
|
||||||
|
adjacent_to_diggers[potential_target] = {periodicity = fields.periodicity, offset = fields.offset}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
cache_all_adjacent_pos[digtron_id] = adjacent
|
||||||
|
cache_all_digger_targets[digtron_id] = adjacent_to_diggers
|
||||||
|
end
|
||||||
|
local retrieve_all_adjacent_pos = function(digtron_id)
|
||||||
|
local val = cache_all_adjacent_pos[digtron_id]
|
||||||
|
if val then return val end
|
||||||
|
refresh_adjacent(digtron_id)
|
||||||
|
return cache_all_adjacent_pos[digtron_id]
|
||||||
|
end
|
||||||
|
local retrieve_all_digger_targets = function(digtron_id)
|
||||||
|
local val = cache_all_digger_targets[digtron_id]
|
||||||
|
if val then return val end
|
||||||
|
refresh_adjacent(digtron_id)
|
||||||
|
return cache_all_digger_targets[digtron_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- call this whenever a stored layout is modified (eg, by rotating it)
|
||||||
|
-- automatically called on dispose
|
||||||
|
local invalidate_layout_cache = function(digtron_id)
|
||||||
|
cache_bounding_box[digtron_id] = nil
|
||||||
|
cache_all_adjacent_pos[digtron_id] = nil
|
||||||
|
cache_all_digger_targets[digtron_id] = nil
|
||||||
|
end
|
||||||
|
table.insert(dispose_callbacks, invalidate_layout_cache)
|
||||||
|
|
||||||
--------------------------------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------------------------------
|
||||||
-- assemble and disassemble
|
-- assemble and disassemble
|
||||||
|
|
||||||
@ -278,8 +362,7 @@ digtron.assemble = function(root_pos, player_name)
|
|||||||
local digtron_nodes = {[root_hash] = node} -- Nodes that are part of Digtron.
|
local digtron_nodes = {[root_hash] = node} -- Nodes that are part of Digtron.
|
||||||
-- Initialize with the controller, it won't be added by get_all_adjacent_digtron_nodes
|
-- Initialize with the controller, it won't be added by get_all_adjacent_digtron_nodes
|
||||||
local digtron_adjacent = {} -- Nodes that are adjacent to Digtron but not a part of it
|
local digtron_adjacent = {} -- Nodes that are adjacent to Digtron but not a part of it
|
||||||
local bounding_box = {minp=vector.new(root_pos), maxp=vector.new(root_pos)}
|
get_all_digtron_nodes(root_pos, digtron_nodes, digtron_adjacent, player_name)
|
||||||
get_all_adjacent_digtron_nodes(root_pos, digtron_nodes, digtron_adjacent, bounding_box, player_name)
|
|
||||||
|
|
||||||
local digtron_id, digtron_inv = create_new_id(root_pos)
|
local digtron_id, digtron_inv = create_new_id(root_pos)
|
||||||
|
|
||||||
@ -329,14 +412,10 @@ digtron.assemble = function(root_pos, player_name)
|
|||||||
layout[relative_hash] = {meta = current_meta_table, node = node}
|
layout[relative_hash] = {meta = current_meta_table, node = node}
|
||||||
end
|
end
|
||||||
|
|
||||||
bounding_box.minp = vector.subtract(bounding_box.minp, root_pos)
|
|
||||||
bounding_box.maxp = vector.subtract(bounding_box.maxp, root_pos)
|
|
||||||
|
|
||||||
digtron.set_name(digtron_id, root_meta:get_string("infotext"))
|
digtron.set_name(digtron_id, root_meta:get_string("infotext"))
|
||||||
persist_inventory(digtron_id)
|
persist_inventory(digtron_id)
|
||||||
persist_layout(digtron_id, layout)
|
persist_layout(digtron_id, layout)
|
||||||
persist_adjacent(digtron_id, digtron_adjacent)
|
invalidate_layout_cache(digtron_id)
|
||||||
persist_bounding_box(digtron_id, bounding_box)
|
|
||||||
persist_pos(digtron_id, root_pos)
|
persist_pos(digtron_id, root_pos)
|
||||||
|
|
||||||
-- Wipe out the inventories of all in-world nodes, it's stored in the mod_meta now.
|
-- Wipe out the inventories of all in-world nodes, it's stored in the mod_meta now.
|
||||||
@ -563,8 +642,6 @@ digtron.build_to_world = function(digtron_id, root_pos, player_name)
|
|||||||
meta:set_string("digtron_id", digtron_id)
|
meta:set_string("digtron_id", digtron_id)
|
||||||
meta:mark_as_private("digtron_id")
|
meta:mark_as_private("digtron_id")
|
||||||
end
|
end
|
||||||
local bbox = retrieve_bounding_box(digtron_id)
|
|
||||||
persist_bounding_box(digtron_id, bbox)
|
|
||||||
persist_pos(digtron_id, root_pos)
|
persist_pos(digtron_id, root_pos)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -597,16 +674,22 @@ digtron.predict_dig = function(digtron_id, player_name)
|
|||||||
local dug_positions = {}
|
local dug_positions = {}
|
||||||
local cost = 0
|
local cost = 0
|
||||||
|
|
||||||
for hash, data in pairs(layout) do
|
for target_hash, digger_data in pairs(retrieve_all_digger_targets(digtron_id)) do
|
||||||
if data.node.name == "digtron:digger" then -- TODO: something better than this based on group, ideally pre-gather this info on assembly
|
local target_pos = minetest.get_position_from_hash(target_hash + root_hash)
|
||||||
local node_pos = minetest.get_position_from_hash(hash + root_hash)
|
|
||||||
local target_pos = vector.add(node_pos, minetest.facedir_to_dir(data.node.param2))
|
|
||||||
if not layout[minetest.hash_node_position(target_pos)] then -- check if the digger is pointed inward, if so ignore it. TODO some way to cull these permanently upon assembly, probably factoring in to the "something better than this" above
|
|
||||||
--TODO protection test, can_dig test, periodicity test
|
|
||||||
--if minetest.get_item_group(target.name, "digtron") ~= 0 or
|
|
||||||
--minetest.get_item_group(target.name, "digtron_protected") ~= 0 or
|
|
||||||
--minetest.get_item_group(target.name, "immortal") ~= 0 then
|
|
||||||
local target_node = minetest.get_node(target_pos)
|
local target_node = minetest.get_node(target_pos)
|
||||||
|
local target_name = target_node.name
|
||||||
|
local targetdef = minetest.registered_nodes[target_name]
|
||||||
|
--TODO periodicity/offset test
|
||||||
|
if minetest.get_item_group(target_name, "digtron") == 0 and
|
||||||
|
minetest.get_item_group(target_name, "digtron_protected") == 0 and
|
||||||
|
minetest.get_item_group(target_name, "immortal") == 0 and
|
||||||
|
(
|
||||||
|
targetdef == nil or -- can dig undefined nodes, why not
|
||||||
|
targetdef.can_dig == nil or
|
||||||
|
targetdef.can_dig(target_pos, minetest.get_player_by_name(player_name))
|
||||||
|
) and
|
||||||
|
not minetest.is_protected(target_pos, player_name)
|
||||||
|
then
|
||||||
|
|
||||||
-- TODO: move this into some kind of shared definition
|
-- TODO: move this into some kind of shared definition
|
||||||
--if digtron.config.uses_resources then
|
--if digtron.config.uses_resources then
|
||||||
@ -627,14 +710,13 @@ digtron.predict_dig = function(digtron_id, player_name)
|
|||||||
-- end
|
-- end
|
||||||
--end
|
--end
|
||||||
|
|
||||||
local drops = minetest.get_node_drops(target_node.name, "")
|
local drops = minetest.get_node_drops(target_name, "")
|
||||||
for _, drop in ipairs(drops) do
|
for _, drop in ipairs(drops) do
|
||||||
products[drop] = (products[drop] or 0) + 1
|
products[drop] = (products[drop] or 0) + 1
|
||||||
end
|
end
|
||||||
table.insert(dug_positions, target_pos)
|
table.insert(dug_positions, target_pos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
return products, dug_positions, cost
|
return products, dug_positions, cost
|
||||||
end
|
end
|
||||||
@ -654,13 +736,11 @@ digtron.can_dig = function(pos, digger)
|
|||||||
|
|
||||||
local node = minetest.get_node(pos)
|
local node = minetest.get_node(pos)
|
||||||
|
|
||||||
local bbox = retrieve_bounding_box(digtron_id)
|
|
||||||
local root_pos = retrieve_pos(digtron_id)
|
local root_pos = retrieve_pos(digtron_id)
|
||||||
local layout = retrieve_layout(digtron_id)
|
local layout = retrieve_layout(digtron_id)
|
||||||
if bbox == nil or root_pos == nil or layout == nil then
|
if root_pos == nil or layout == nil then
|
||||||
-- Somehow, this belongs to a digtron id that's missing information that should exist in persistence.
|
-- Somehow, this belongs to a digtron id that's missing information that should exist in persistence.
|
||||||
local missing = ""
|
local missing = ""
|
||||||
if bbox == nil then missing = missing .. "bounding_box " end
|
|
||||||
if root_pos == nil then missing = missing .. "root_pos " end
|
if root_pos == nil then missing = missing .. "root_pos " end
|
||||||
if layout == nil then missing = missing .. "layout " end
|
if layout == nil then missing = missing .. "layout " end
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ minetest.register_node("digtron:digger", {
|
|||||||
},
|
},
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
groups = {cracky = 3, oddly_breakable_by_hand = 3, digtron = 1},
|
groups = {cracky = 3, oddly_breakable_by_hand = 3, digtron = 3},
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
sounds = default.node_sound_metal_defaults(),
|
sounds = default.node_sound_metal_defaults(),
|
||||||
can_dig = digtron.can_dig,
|
can_dig = digtron.can_dig,
|
||||||
@ -79,7 +79,7 @@ minetest.register_node("digtron:digger_static",{
|
|||||||
},
|
},
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
groups = {cracky = 3, oddly_breakable_by_hand = 3, digtron = 1},
|
groups = {cracky = 3, oddly_breakable_by_hand = 3, digtron = 3},
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
sounds = default.node_sound_metal_defaults(),
|
sounds = default.node_sound_metal_defaults(),
|
||||||
can_dig = digtron.can_dig,
|
can_dig = digtron.can_dig,
|
||||||
|
Loading…
Reference in New Issue
Block a user