This commit is contained in:
FaceDeer 2019-08-25 15:52:35 -06:00
parent 683b941622
commit 426cd4d82d
4 changed files with 82 additions and 48 deletions

@ -260,10 +260,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
if fields.test_dig then
local products, nodes_to_dig, cost = digtron.predict_dig(digtron_id, player_name)
minetest.chat_send_all("products: " .. dump(products))
minetest.chat_send_all("positions: " .. dump(nodes_to_dig))
minetest.chat_send_all("cost: " .. cost)
digtron.execute_cycle(digtron_id, player_name)
end
--TODO: this isn't recording the field when using ESC to exit the formspec

@ -19,7 +19,7 @@ local get_predictive_inventory = inventory_functions.get_predictive_inventory
local commit_predictive_inventory = inventory_functions.commit_predictive_inventory
local clear_predictive_inventory = inventory_functions.clear_predictive_inventory
digtron.retrieve_inventory = retrieve_inventory
digtron.retrieve_inventory = retrieve_inventory -- used by formspecs
--------------------------------------------------------------------------------------
@ -134,7 +134,8 @@ for i, dir in ipairs(cardinal_dirs) do
cardinal_dirs_hash[i] = minetest.hash_node_position(dir) - minetest.hash_node_position({x=0, y=0, z=0})
end
-- Given a facedir, returns an index into either cardinal_dirs or cardinal_dirs_hash that
-- Given a facedir, returns an index into either cardinal_dirs or cardinal_dirs_hash that
-- can be used to determine what this node is "aimed" at
local facedir_to_dir_index = function(param2)
return facedir_to_dir_map[param2 % 32]
end
@ -160,7 +161,7 @@ get_all_digtron_nodes = function(pos, digtron_nodes, digtron_adjacent, player_na
get_all_digtron_nodes(test_pos, digtron_nodes, digtron_adjacent, player_name) -- recurse
end
else
-- don't record details, the content of this node will change as the digtron moves
-- don't record details, just keeping track of Digtron's borders
digtron_adjacent[test_hash] = true
end
end
@ -267,7 +268,9 @@ digtron.assemble = function(root_pos, player_name)
local root_hash = minetest.hash_node_position(root_pos)
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
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.
-- There's a slight inefficiency in throwing away digtron_adjacent when retrieve_all_adjacent_pos could
-- use this info, but it's small and IMO not worth the complexity.
get_all_digtron_nodes(root_pos, digtron_nodes, digtron_adjacent, player_name)
local digtron_id, digtron_inv = create_new_id(root_pos)
@ -352,7 +355,6 @@ digtron.assemble = function(root_pos, player_name)
return digtron_id
end
-- Returns pos, node, and meta for the digtron node provided the in-world node matches the layout
-- returns nil otherwise
local get_valid_data = function(digtron_id, root_hash, hash, data, function_name)
@ -500,18 +502,22 @@ digtron.remove_from_world = function(digtron_id, player_name)
end
-- Tests if a Digtron can be built at the designated location
--TODO implement ignore_nodes, needed for ignoring nodes that have been flagged as dug
digtron.is_buildable_to = function(digtron_id, root_pos, player_name, ignore_nodes, return_immediately_on_failure)
local layout = retrieve_layout(digtron_id)
-- If this digtron is already in-world, we're likely testing as part of a movement attempt.
-- Record its existing node locations, they will be treated as buildable_to
local old_pos = retrieve_pos(digtron_id)
local old_hashes = {}
local ignore_hashes = {}
if old_pos then
local old_root_hash = minetest.hash_node_position(old_pos)
for layout_hash, _ in pairs(layout) do
old_hashes[layout_hash + old_root_hash] = true
ignore_hashes[layout_hash + old_root_hash] = true
end
end
if ignore_nodes then
for _, ignore_pos in ipairs(ignore_nodes) do
ignore_hashes[minetest.hash_node_position(ignore_pos)] = true
end
end
@ -529,7 +535,7 @@ digtron.is_buildable_to = function(digtron_id, root_pos, player_name, ignore_nod
-- TODO: lots of testing needed here
if not (
(node_def and node_def.buildable_to)
or old_hashes[node_hash]) or
or ignore_hashes[node_hash]) or
minetest.is_protected(target_pos, player_name)
then
if return_immediately_on_failure then
@ -568,7 +574,6 @@ digtron.build_to_world = function(digtron_id, root_pos, player_name)
end
digtron.move = function(digtron_id, dest_pos, player_name)
minetest.chat_send_all("move attempt")
local permitted, succeeded, failed = digtron.is_buildable_to(digtron_id, dest_pos, player_name)
if permitted then
local removed = digtron.remove_from_world(digtron_id, player_name)
@ -583,13 +588,18 @@ digtron.move = function(digtron_id, dest_pos, player_name)
end
end
digtron.predict_dig = function(digtron_id, player_name)
local predict_dig = function(digtron_id, player_name)
local predictive_inv = get_predictive_inventory(digtron_id)
local layout = retrieve_layout(digtron_id)
local root_pos = retrieve_pos(digtron_id)
if not (layout and root_pos) then return end -- TODO error messages etc
if not (layout and root_pos and predictive_inv) then
minetest.log("error", "[Digtron] predict_dig failed to retrieve either "
.."a predictive inventory, a layout, or a root position for " .. digtron_id)
return
end
local root_hash = minetest.hash_node_position(root_pos)
local products = {}
local leftovers = {}
local dug_positions = {}
local cost = 0
@ -634,15 +644,45 @@ digtron.predict_dig = function(digtron_id, player_name)
local drops = minetest.get_node_drops(target_name, "")
for _, drop in ipairs(drops) do
products[drop] = (products[drop] or 0) + 1
local leftover = predictive_inv:add_item("main", ItemStack(drop))
if leftover:get_count() > 0 then
table.insert(leftovers, leftover)
end
end
table.insert(dug_positions, target_pos)
end
end
return products, dug_positions, cost
return leftovers, dug_positions, cost
end
digtron.execute_cycle = function(digtron_id, player_name)
local leftovers, nodes_to_dig, cost = predict_dig(digtron_id, player_name)
local root_pos = retrieve_pos(digtron_id)
local root_node = minetest.get_node(root_pos)
local new_pos = vector.add(root_pos, cardinal_dirs[facedir_to_dir_index(root_node.param2)])
local buildable_to, succeeded, failed = digtron.is_buildable_to(digtron_id, new_pos, player_name, nodes_to_dig, return_immediately_on_failure)
if buildable_to then
local removed = digtron.remove_from_world(digtron_id, player_name)
minetest.bulk_set_node(nodes_to_dig, {name="air"})
digtron.build_to_world(digtron_id, new_pos, player_name)
minetest.sound_play("digtron_construction", {gain = 0.5, pos=new_pos})
for _, removed_pos in ipairs(removed) do
minetest.check_for_falling(removed_pos)
end
for _, dug_pos in ipairs(nodes_to_dig) do
-- TODO: other on-dug callbacks
minetest.check_for_falling(dug_pos)
end
commit_predictive_inventory(digtron_id)
else
digtron.show_buildable_nodes({}, failed)
minetest.sound_play("digtron_squeal", {gain = 0.5, pos=new_pos})
end
end
---------------------------------------------------------------------------------
-- Node callbacks

@ -110,40 +110,21 @@ local predictive_inventory = {}
-- Copies digtron's inventory into a temporary location so that a dig cycle can be run
-- using it without affecting the actual inventory until everything's been confirmed to work
local get_predictive_inventory = function(digtron_id)
local existing = predictive_inventory[digtron_id]
if existing then return existing end
local predictive_inv = minetest.create_detached_inventory("digtron_predictive_"..digtron_id, detached_inventory_callbacks)
predictive_inventory[digtron_id] = predictive_inv
local source_inv = digtron.retrieve_inventory(digtron_id)
local source_inv = retrieve_inventory(digtron_id)
-- Populate predictive inventory with the digtron's contents
for _, listname in ipairs(source_inv:get_lists()) do
predictive_inv:set_size(listname, source_inv:get_size(listname))
predictive_inv:set_list(listname, source_inv:get_list(listname))
for listname, invlist in pairs(source_inv:get_lists()) do
predictive_inv:set_size(listname, #invlist)
predictive_inv:set_list(listname, invlist)
end
return predictive_inv
end
-- Copies the predictive inventory's contents into the actual digtron's inventory after success
local commit_predictive_inventory = function(digtron_id)
local predictive_inv = predictive_inventory[digtron_id]
if not predictive_inv then
minetest.log("error", "[Digtron] commit_predictive_inventory called for " .. digtron_id
.. " but predictive inventory did not exist")
return
end
local source_inv = digtron.retrieve_inventory(digtron_id)
for _, listname in ipairs(predictive_inv:get_lists()) do
source_inv:set_list(listname, predictive_inv:get_list(listname))
end
dirty_inventories[digtron_id] = true
minetest.remove_detached_inventory("digtron_predictive_"..digtron_id)
predictive_inventory[digtron_id] = nil
if not next(predictive_inventory) then
minetest.log("warning", "[Digtron] multiple predictive inventories were in existence, this shouldn't be happening. File an issue with Digtron programmers.")
end
end
-- Wipes predictive inventory without committing it (eg, on failure of predicted operation)
local clear_predictive_inventory = function(digtron_id)
local predictive_inv = predictive_inventory[digtron_id]
@ -160,6 +141,22 @@ local clear_predictive_inventory = function(digtron_id)
minetest.log("warning", "[Digtron] multiple predictive inventories were in existence, this shouldn't be happening. File an issue with Digtron programmers.")
end
end
-- Copies the predictive inventory's contents into the actual digtron's inventory and wipes the predictive inventory
local commit_predictive_inventory = function(digtron_id)
local predictive_inv = predictive_inventory[digtron_id]
if not predictive_inv then
minetest.log("error", "[Digtron] commit_predictive_inventory called for " .. digtron_id
.. " but predictive inventory did not exist")
return
end
local source_inv = retrieve_inventory(digtron_id)
for listname, invlist in pairs(predictive_inv:get_lists()) do
source_inv:set_list(listname, invlist)
end
dirty_inventories[digtron_id] = true
clear_predictive_inventory(digtron_id)
end
return {
retrieve_inventory = retrieve_inventory,

@ -24,7 +24,7 @@ minetest.register_node("digtron:inventory", {
_doc_items_longdesc = digtron.doc.inventory_longdesc,
_doc_items_usagehelp = digtron.doc.inventory_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 2, tubedevice = 1, tubedevice_receiver = 1},
sounds = digtron.metal_sounds,
sounds = default.node_sound_metal_defaults(),
paramtype2= "facedir",
drawtype = "nodebox",
node_box = {
@ -112,7 +112,7 @@ minetest.register_node("digtron:fuelstore", {
_doc_items_longdesc = digtron.doc.fuelstore_longdesc,
_doc_items_usagehelp = digtron.doc.fuelstore_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 5, tubedevice = 1, tubedevice_receiver = 1},
sounds = digtron.metal_sounds,
sounds = default.node_sound_metal_defaults(),
paramtype2= "facedir",
drawtype = "nodebox",
node_box = {
@ -220,7 +220,7 @@ minetest.register_node("digtron:combined_storage", {
_doc_items_longdesc = digtron.doc.combined_storage_longdesc,
_doc_items_usagehelp = digtron.doc.combined_storage_usagehelp,
groups = {cracky = 3, oddly_breakable_by_hand=3, digtron = 6, tubedevice = 1, tubedevice_receiver = 1},
sounds = digtron.metal_sounds,
sounds = default.node_sound_metal_defaults(),
paramtype2= "facedir",
drawtype = "nodebox",
node_box = {