mirror of
https://github.com/minetest-mods/digtron.git
synced 2024-08-19 20:34:04 +02:00
bring back the hacked item place function
This commit is contained in:
parent
e0d02704a6
commit
256ec951e2
@ -119,14 +119,7 @@ local cardinal_dirs = {
|
|||||||
}
|
}
|
||||||
digtron.cardinal_dirs = cardinal_dirs -- used by builder entities as well
|
digtron.cardinal_dirs = cardinal_dirs -- used by builder entities as well
|
||||||
-- Mapping from facedir value to index in cardinal_dirs.
|
-- Mapping from facedir value to index in cardinal_dirs.
|
||||||
local facedir_to_dir_map = {
|
local facedir_to_dir_map = digtron.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,
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Turn the cardinal directions into a set of integers you can add to a hash to step in that direction.
|
-- Turn the cardinal directions into a set of integers you can add to a hash to step in that direction.
|
||||||
local cardinal_dirs_hash = {}
|
local cardinal_dirs_hash = {}
|
||||||
@ -225,10 +218,11 @@ local refresh_adjacent = function(digtron_id)
|
|||||||
if layout[potential_target] == nil then
|
if layout[potential_target] == nil then
|
||||||
local fields = data.meta.fields
|
local fields = data.meta.fields
|
||||||
adjacent_to_builders[potential_target] = {
|
adjacent_to_builders[potential_target] = {
|
||||||
period = fields.period,
|
period = tonumber(fields.period) or 1,
|
||||||
offset = fields.offset,
|
offset = tonumber(fields.offset) or 0,
|
||||||
item = fields.item,
|
item = fields.item,
|
||||||
facing = fields.facing,
|
facing = tonumber(fields.facing) or 0,
|
||||||
|
extrusion = tonumber(fields.extrusion) or 1,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -783,6 +777,8 @@ local predict_build = function(digtron_id, new_pos, player_name, ignore_nodes)
|
|||||||
cost = cost + digtron.config.build_cost
|
cost = cost + digtron.config.build_cost
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- TODO handle extrusion
|
||||||
|
|
||||||
table.insert(built_nodes, {
|
table.insert(built_nodes, {
|
||||||
pos = target_pos,
|
pos = target_pos,
|
||||||
node = {name=item, param2=facing },
|
node = {name=item, param2=facing },
|
||||||
@ -795,11 +791,18 @@ local predict_build = function(digtron_id, new_pos, player_name, ignore_nodes)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local build_nodes = function(built_nodes)
|
local build_nodes = function(built_nodes)
|
||||||
|
local leftovers = {}
|
||||||
for _, build_info in ipairs(built_nodes) do
|
for _, build_info in ipairs(built_nodes) do
|
||||||
-- TODO: much more complicated than this, see hacked place_item method and stuff
|
local item_stack = ItemStack(build_info.node.name)
|
||||||
minetest.set_node(build_info.pos, build_info.node)
|
local buildpos = build_info.pos
|
||||||
|
local build_facing = build_info.node.param2
|
||||||
|
local returned_stack, success = digtron.item_place_node(item_stack, digtron.fake_player, buildpos, build_facing)
|
||||||
|
if returned_stack:get_count() > 0 then
|
||||||
|
table.insert(leftovers, returned_stack)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
return leftovers
|
||||||
|
end
|
||||||
|
|
||||||
local execute_built_callbacks = function(built_nodes)
|
local execute_built_callbacks = function(built_nodes)
|
||||||
for _, build_info in ipairs(built_nodes) do
|
for _, build_info in ipairs(built_nodes) do
|
||||||
@ -825,7 +828,7 @@ end
|
|||||||
-- Execute cycle
|
-- Execute cycle
|
||||||
|
|
||||||
digtron.execute_cycle = function(digtron_id, player_name)
|
digtron.execute_cycle = function(digtron_id, player_name)
|
||||||
local leftovers, nodes_to_dig, dig_cost = predict_dig(digtron_id, player_name)
|
local dig_leftovers, nodes_to_dig, dig_cost = predict_dig(digtron_id, player_name)
|
||||||
local old_root_pos = retrieve_pos(digtron_id)
|
local old_root_pos = retrieve_pos(digtron_id)
|
||||||
local root_node = minetest.get_node(old_root_pos)
|
local root_node = minetest.get_node(old_root_pos)
|
||||||
local new_root_pos = vector.add(old_root_pos, cardinal_dirs[facedir_to_dir_index(root_node.param2)])
|
local new_root_pos = vector.add(old_root_pos, cardinal_dirs[facedir_to_dir_index(root_node.param2)])
|
||||||
@ -845,7 +848,8 @@ digtron.execute_cycle = function(digtron_id, player_name)
|
|||||||
digtron.build_to_world(digtron_id, new_root_pos, player_name)
|
digtron.build_to_world(digtron_id, new_root_pos, player_name)
|
||||||
minetest.sound_play("digtron_construction", {gain = 0.5, pos=new_root_pos})
|
minetest.sound_play("digtron_construction", {gain = 0.5, pos=new_root_pos})
|
||||||
|
|
||||||
build_nodes(built_nodes)
|
local build_leftovers = build_nodes(built_nodes, player_name)
|
||||||
|
-- There shouldn't normally be build_leftovers, but it's possible.
|
||||||
|
|
||||||
-- Don't need to do fancy callback checking for digtron nodes since I made all those
|
-- Don't need to do fancy callback checking for digtron nodes since I made all those
|
||||||
-- nodes and I know they don't have anything that needs to be done for them.
|
-- nodes and I know they don't have anything that needs to be done for them.
|
||||||
@ -858,6 +862,8 @@ digtron.execute_cycle = function(digtron_id, player_name)
|
|||||||
execute_dug_callbacks(nodes_dug)
|
execute_dug_callbacks(nodes_dug)
|
||||||
execute_built_callbacks(built_nodes)
|
execute_built_callbacks(built_nodes)
|
||||||
|
|
||||||
|
-- TODO try putting dig_leftovers and build_leftovers into the inventory one last time before ejecting it
|
||||||
|
|
||||||
commit_predictive_inventory(digtron_id)
|
commit_predictive_inventory(digtron_id)
|
||||||
else
|
else
|
||||||
clear_predictive_inventory(digtron_id)
|
clear_predictive_inventory(digtron_id)
|
||||||
|
22
init.lua
22
init.lua
@ -1,15 +1,33 @@
|
|||||||
digtron = {}
|
digtron = {}
|
||||||
digtron.doc = {} -- TODO: move to doc file
|
digtron.doc = {} -- TODO: move to doc file
|
||||||
|
|
||||||
|
|
||||||
|
-- Sometimes we want builder heads to call an item's "on_place" method, other times we
|
||||||
|
-- don't want them to. There's no way to tell which situation is best programmatically
|
||||||
|
-- so we have to rely on whitelists to be on the safe side.
|
||||||
|
--first exact matches are tested, and the value given in this global table is returned
|
||||||
|
digtron.builder_on_place_items = {
|
||||||
|
["default:torch"] = true,
|
||||||
|
}
|
||||||
|
-- Then a string prefix is checked, returning this value. Useful for enabling on_placed on a mod-wide basis.
|
||||||
|
digtron.builder_on_place_prefixes = {
|
||||||
|
["farming:"] = true,
|
||||||
|
["farming_plus:"] = true,
|
||||||
|
["crops:"] = true,
|
||||||
|
}
|
||||||
|
-- Finally, items belonging to group "digtron_on_place" will have their on_place methods called.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
digtron.mod_meta = minetest.get_mod_storage()
|
digtron.mod_meta = minetest.get_mod_storage()
|
||||||
|
|
||||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||||
|
dofile(modpath.."/config.lua")
|
||||||
|
|
||||||
dofile(modpath.."/class_fakeplayer.lua")
|
dofile(modpath.."/class_fakeplayer.lua")
|
||||||
digtron.fake_player = DigtronFakePlayer.create({x=0,y=0,z=0}, "fake_player") -- since we only need one fake player at a time and it doesn't retain useful state, create a global one and just update it as needed.
|
digtron.fake_player = DigtronFakePlayer.create({x=0,y=0,z=0}, "fake_player") -- since we only need one fake player at a time and it doesn't retain useful state, create a global one and just update it as needed.
|
||||||
|
dofile(modpath.."/util_item_place_node.lua")
|
||||||
|
|
||||||
dofile(modpath.."/config.lua")
|
|
||||||
dofile(modpath.."/entities.lua")
|
dofile(modpath.."/entities.lua")
|
||||||
dofile(modpath.."/functions.lua")
|
dofile(modpath.."/functions.lua")
|
||||||
dofile(modpath.."/controller.lua")
|
dofile(modpath.."/controller.lua")
|
||||||
|
@ -78,6 +78,16 @@ local inv = minetest.create_detached_inventory("digtron:builder_item", {
|
|||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local stack_def = minetest.registered_nodes[item]
|
||||||
|
if not stack_def and not digtron.whitelisted_on_place(item) then
|
||||||
|
return 0 -- don't allow craft items unless their on_place is whitelisted.
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If we're adding a wallmounted item and the build facing is greater than 5, reset it to 0
|
||||||
|
if stack_def ~= nil and stack_def.paramtype2 == "wallmounted" and tonumber(meta:get_int("facing")) > 5 then
|
||||||
|
meta:set_int("facing", 0)
|
||||||
|
end
|
||||||
|
|
||||||
meta:set_string("item", item)
|
meta:set_string("item", item)
|
||||||
digtron.update_builder_item(pos)
|
digtron.update_builder_item(pos)
|
||||||
minetest.show_formspec(player_name, "digtron:builder", get_formspec(pos))
|
minetest.show_formspec(player_name, "digtron:builder", get_formspec(pos))
|
||||||
@ -140,29 +150,31 @@ minetest.register_on_player_receive_fields(function(sender, formname, fields)
|
|||||||
local extrusion = tonumber(fields.extrusion)
|
local extrusion = tonumber(fields.extrusion)
|
||||||
|
|
||||||
if period and period > 0 then
|
if period and period > 0 then
|
||||||
meta:set_int("period", math.floor(tonumber(fields.period)))
|
meta:set_int("period", math.floor(period))
|
||||||
else
|
else
|
||||||
period = meta:get_int("period")
|
period = meta:get_int("period")
|
||||||
end
|
end
|
||||||
if offset then
|
if offset then
|
||||||
meta:set_int("offset", math.floor(tonumber(fields.offset)))
|
meta:set_int("offset", math.floor(offset))
|
||||||
else
|
else
|
||||||
offset = meta:get_int("offset")
|
offset = meta:get_int("offset")
|
||||||
end
|
end
|
||||||
if facing and facing >= 0 and facing < 24 then
|
if facing and facing >= 0 and facing < 24 then
|
||||||
local inv = meta:get_inventory()
|
local target_item = ItemStack(meta:get_string("item"))
|
||||||
local target_item = inv:get_stack("main",1)
|
|
||||||
if target_item:get_definition().paramtype2 == "wallmounted" then
|
if target_item:get_definition().paramtype2 == "wallmounted" then
|
||||||
if facing < 6 then
|
if facing < 6 then
|
||||||
meta:set_int("facing", math.floor(facing))
|
meta:set_int("facing", facing)
|
||||||
-- wallmounted facings only run from 0-5
|
-- wallmounted facings only run from 0-5
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
meta:set_int("facing", math.floor(facing))
|
meta:set_int("facing", math.floor(facing))
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
facing = meta:get_int("facing")
|
||||||
end
|
end
|
||||||
|
|
||||||
if extrusion and extrusion > 0 and extrusion <= digtron.config.maximum_extrusion then
|
if extrusion and extrusion > 0 and extrusion <= digtron.config.maximum_extrusion then
|
||||||
meta:set_int("extrusion", math.floor(tonumber(fields.extrusion)))
|
meta:set_int("extrusion", math.floor(extrusion))
|
||||||
else
|
else
|
||||||
extrusion = meta:get_int("extrusion")
|
extrusion = meta:get_int("extrusion")
|
||||||
end
|
end
|
||||||
|
181
util_item_place_node.lua
Normal file
181
util_item_place_node.lua
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
-- The default minetest.item_place_node from item.lua was hard to work with given some of the details
|
||||||
|
-- of how it handled pointed_thing. It also didn't work right with default:torch and seeds. It was simpler to
|
||||||
|
-- just copy it here and chop out the special cases that were causing problems, and add some special handling.
|
||||||
|
-- for nodes that define on_place
|
||||||
|
|
||||||
|
-- This specific file is therefore licensed under the LGPL 2.1
|
||||||
|
|
||||||
|
--GNU Lesser General Public License, version 2.1
|
||||||
|
--Copyright (C) 2011-2016 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||||
|
--Copyright (C) 2011-2016 Various Minetest developers and contributors
|
||||||
|
|
||||||
|
--This program is free software; you can redistribute it and/or modify it under the terms
|
||||||
|
--of the GNU Lesser General Public License as published by the Free Software Foundation;
|
||||||
|
--either version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
--This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
--without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
--See the GNU Lesser General Public License for more details:
|
||||||
|
--https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
|
||||||
|
|
||||||
|
-- Mapping from facedir value to index in facedir_to_dir.
|
||||||
|
digtron.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 function has_prefix(str, prefix)
|
||||||
|
return str:sub(1, string.len(prefix)) == prefix
|
||||||
|
end
|
||||||
|
|
||||||
|
digtron.whitelisted_on_place = function (item_name)
|
||||||
|
for listed_item, value in pairs(digtron.builder_on_place_items) do
|
||||||
|
if item_name == listed_item then return value end
|
||||||
|
end
|
||||||
|
|
||||||
|
for prefix, value in pairs(digtron.builder_on_place_prefixes) do
|
||||||
|
if has_prefix(item_name, prefix) then return value end
|
||||||
|
end
|
||||||
|
|
||||||
|
if minetest.get_item_group(item_name, "digtron_on_place") > 0 then return true end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function copy_pointed_thing(pointed_thing)
|
||||||
|
return {
|
||||||
|
type = pointed_thing.type,
|
||||||
|
above = vector.new(pointed_thing.above),
|
||||||
|
under = vector.new(pointed_thing.under),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function check_attached_node(p, n)
|
||||||
|
local def = minetest.registered_nodes[n.name]
|
||||||
|
local d = {x = 0, y = 0, z = 0}
|
||||||
|
if def.paramtype2 == "wallmounted" then
|
||||||
|
-- The fallback vector here is in case 'wallmounted to dir' is nil due
|
||||||
|
-- to voxelmanip placing a wallmounted node without resetting a
|
||||||
|
-- pre-existing param2 value that is out-of-range for wallmounted.
|
||||||
|
-- The fallback vector corresponds to param2 = 0.
|
||||||
|
d = minetest.wallmounted_to_dir(n.param2) or {x = 0, y = 1, z = 0}
|
||||||
|
else
|
||||||
|
d.y = -1
|
||||||
|
end
|
||||||
|
local p2 = vector.add(p, d)
|
||||||
|
local nn = minetest.get_node(p2).name
|
||||||
|
local def2 = minetest.registered_nodes[nn]
|
||||||
|
if def2 and not def2.walkable then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
digtron.item_place_node = function(itemstack, placer, place_to, param2)
|
||||||
|
local item_name = itemstack:get_name()
|
||||||
|
local def = itemstack:get_definition()
|
||||||
|
if (not def) or (param2 < 0) or (def.paramtype2 == "wallmounted" and param2 > 5) or (param2 > 23) then -- validate parameters
|
||||||
|
return itemstack, false
|
||||||
|
end
|
||||||
|
|
||||||
|
local pointed_thing = {}
|
||||||
|
pointed_thing.type = "node"
|
||||||
|
pointed_thing.above = {x=place_to.x, y=place_to.y, z=place_to.z}
|
||||||
|
pointed_thing.under = {x=place_to.x, y=place_to.y - 1, z=place_to.z}
|
||||||
|
|
||||||
|
-- Handle node-specific on_place calls as best we can.
|
||||||
|
if def.on_place and def.on_place ~= minetest.nodedef_default.on_place and digtron.whitelisted_on_place(item_name) then
|
||||||
|
if def.paramtype2 == "facedir" then
|
||||||
|
pointed_thing.under = vector.add(place_to, minetest.facedir_to_dir(param2))
|
||||||
|
elseif def.paramtype2 == "wallmounted" then
|
||||||
|
pointed_thing.under = vector.add(place_to, minetest.wallmounted_to_dir(param2))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- pass a copy of the item stack parameter because on_place might modify it directly and then we can't tell if we succeeded or not
|
||||||
|
-- though note that some mods do "creative_mode" handling within their own on_place methods, which makes it impossible for Digtron
|
||||||
|
-- to know what to do in that case - if you're in creative_mode Digtron will place such items but it will think it failed and not
|
||||||
|
-- deduct them from inventory no matter what Digtron's settings are. Unfortunate, but not very harmful and I have no workaround.
|
||||||
|
local returnstack, success = def.on_place(ItemStack(itemstack), placer, pointed_thing)
|
||||||
|
if returnstack and returnstack:get_count() < itemstack:get_count() then success = true end -- some mods neglect to return a success condition
|
||||||
|
if success then
|
||||||
|
-- Override the param2 value to force it to be what Digtron wants
|
||||||
|
local placed_node = minetest.get_node(place_to)
|
||||||
|
placed_node.param2 = param2
|
||||||
|
minetest.set_node(place_to, placed_node)
|
||||||
|
end
|
||||||
|
|
||||||
|
return returnstack, success
|
||||||
|
end
|
||||||
|
|
||||||
|
if minetest.registered_nodes[item_name] == nil then
|
||||||
|
-- Permitted craft items are handled by the node-specific on_place call, above.
|
||||||
|
-- if we are a craft item and we get here then we're not whitelisted and we should fail.
|
||||||
|
-- Note that builder settings should be filtering out craft items like this before we get here,
|
||||||
|
-- but this will protect us just in case.
|
||||||
|
return itemstack, false
|
||||||
|
end
|
||||||
|
|
||||||
|
local oldnode = minetest.get_node_or_nil(place_to)
|
||||||
|
|
||||||
|
--this should never happen, digtron is testing for adjacent unloaded nodes before getting here.
|
||||||
|
if not oldnode then
|
||||||
|
minetest.log("info", placer:get_player_name() .. " tried to place"
|
||||||
|
.. " node in unloaded position " .. minetest.pos_to_string(place_to)
|
||||||
|
.. " using a digtron.")
|
||||||
|
return itemstack, false
|
||||||
|
end
|
||||||
|
|
||||||
|
local newnode = {name = def.name, param1 = 0, param2 = param2}
|
||||||
|
if def.place_param2 ~= nil then
|
||||||
|
newnode.param2 = def.place_param2
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if the node is attached and if it can be placed there
|
||||||
|
if minetest.get_item_group(def.name, "attached_node") ~= 0 and
|
||||||
|
not check_attached_node(place_to, newnode) then
|
||||||
|
minetest.log("action", "attached node " .. def.name ..
|
||||||
|
" can not be placed at " .. minetest.pos_to_string(place_to))
|
||||||
|
return itemstack, false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add node and update
|
||||||
|
minetest.add_node(place_to, newnode)
|
||||||
|
|
||||||
|
local take_item = true
|
||||||
|
|
||||||
|
-- Run callback, using genuine player for per-node definition.
|
||||||
|
if def.after_place_node then
|
||||||
|
-- Deepcopy place_to and pointed_thing because callback can modify it
|
||||||
|
local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
|
||||||
|
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
|
||||||
|
if def.after_place_node(place_to_copy, placer, itemstack,
|
||||||
|
pointed_thing_copy) then
|
||||||
|
take_item = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Run script hook, using fake_player to take the blame.
|
||||||
|
-- Note that fake_player:update is called in the DigtronLayout class's "create" function,
|
||||||
|
-- which is called before Digtron does any of this building stuff, so it's not necessary
|
||||||
|
-- to update it here.
|
||||||
|
local _, callback
|
||||||
|
for _, callback in ipairs(minetest.registered_on_placenodes) do
|
||||||
|
-- Deepcopy pos, node and pointed_thing because callback can modify them
|
||||||
|
local place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
|
||||||
|
local newnode_copy = {name=newnode.name, param1=newnode.param1, param2=newnode.param2}
|
||||||
|
local oldnode_copy = {name=oldnode.name, param1=oldnode.param1, param2=oldnode.param2}
|
||||||
|
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
|
||||||
|
if callback(place_to_copy, newnode_copy, digtron.fake_player, oldnode_copy, itemstack, pointed_thing_copy) then
|
||||||
|
take_item = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if take_item then
|
||||||
|
itemstack:take_item()
|
||||||
|
end
|
||||||
|
return itemstack, true
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user