mirror of
https://github.com/minetest-mods/digtron.git
synced 2025-01-03 01:27:28 +01:00
fakeplayer for callbacks, switch to whitelist for on_place calls
This commit is contained in:
parent
0430d423f7
commit
abc7f2e414
145
class_fakeplayer.lua
Normal file
145
class_fakeplayer.lua
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
-- The purpose of this class is to have something that can be passed into callbacks that
|
||||||
|
-- demand a "Player" object as a parameter and hopefully prevent the mods that have
|
||||||
|
-- registered with those callbacks from crashing on a nil dereference or bad function
|
||||||
|
-- call. This is not supposed to be a remotely functional thing, it's just supposed
|
||||||
|
-- to provide dummy methods and return values of the correct data type for anything that
|
||||||
|
-- might ignore the false "is_player()" return and go ahead and try to use this thing
|
||||||
|
-- anyway.
|
||||||
|
|
||||||
|
-- I'm trying to patch holes in bad mod programming, essentially. If a mod is so badly
|
||||||
|
-- programmed that it crashes anyway there's not a lot else I can do on my end of things.
|
||||||
|
|
||||||
|
DigtronFakePlayer = {}
|
||||||
|
DigtronFakePlayer.__index = DigtronFakePlayer
|
||||||
|
|
||||||
|
local function return_value(x)
|
||||||
|
return (function() return x end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function return_nil()
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function return_empty_string()
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
local function return_zero()
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local function return_empty_table()
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
function DigtronFakePlayer.update(self, pos, player_name)
|
||||||
|
self.is_fake_player = ":digtron " .. player_name
|
||||||
|
self.get_pos = return_value(pos)
|
||||||
|
end
|
||||||
|
|
||||||
|
function DigtronFakePlayer.create(pos, player_name)
|
||||||
|
local self = {}
|
||||||
|
setmetatable(self, DigtronFakePlayer)
|
||||||
|
|
||||||
|
self.is_fake_player = ":digtron " .. player_name
|
||||||
|
|
||||||
|
-- ObjectRef
|
||||||
|
self.get_pos = return_value(pos)
|
||||||
|
self.set_pos = return_nil
|
||||||
|
self.move_to = return_nil
|
||||||
|
self.punch = return_nil
|
||||||
|
self.right_click = return_nil
|
||||||
|
self.get_hp = return_value(10)
|
||||||
|
self.set_hp = return_nil
|
||||||
|
self.get_inventory = return_nil -- returns an `InvRef`
|
||||||
|
self.get_wield_list = return_empty_string
|
||||||
|
self.get_wield_index = return_value(1)
|
||||||
|
self.get_wielded_item = return_value(ItemStack(nil))
|
||||||
|
self.set_wielded_item = return_value(false)
|
||||||
|
self.set_armor_groups = return_nil
|
||||||
|
self.get_armor_groups = return_empty_table
|
||||||
|
self.set_animation = return_nil
|
||||||
|
self.get_animation = return_nil -- a set of values, maybe important?
|
||||||
|
self.set_attach = return_nil
|
||||||
|
self.get_attach = return_nil
|
||||||
|
self.set_detach = return_nil
|
||||||
|
self.set_bone_position = return_nil
|
||||||
|
self.get_bone_position = return_nil
|
||||||
|
self.set_properties = return_nil
|
||||||
|
self.get_properties = return_empty_table
|
||||||
|
|
||||||
|
self.is_player = return_value(false)
|
||||||
|
|
||||||
|
self.get_nametag_attributes = return_empty_table
|
||||||
|
self.set_nametag_attributes = return_nil
|
||||||
|
|
||||||
|
--LuaEntitySAO
|
||||||
|
self.set_velocity = return_nil
|
||||||
|
self.get_velocity = return_value({x=0,y=0,z=0})
|
||||||
|
self.set_acceleration = return_nil
|
||||||
|
self.get_acceleration = return_value({x=0,y=0,z=0})
|
||||||
|
self.set_yaw = return_nil
|
||||||
|
self.get_yaw = return_zero
|
||||||
|
self.set_texture_mod = return_nil
|
||||||
|
self.get_texture_mod = return_nil -- maybe important?
|
||||||
|
self.set_sprite = return_nil
|
||||||
|
--self.get_entity_name` (**Deprecated**: Will be removed in a future version)
|
||||||
|
self.get_luaentity = return_nil
|
||||||
|
|
||||||
|
-- Player object
|
||||||
|
|
||||||
|
self.get_player_name = return_empty_string
|
||||||
|
self.get_player_velocity = return_nil
|
||||||
|
self.get_look_dir = return_value({x=0,y=1,z=0})
|
||||||
|
self.get_look_horizontal = return_zero
|
||||||
|
self.set_look_horizontal = return_nil
|
||||||
|
self.get_look_vertical = return_zero
|
||||||
|
self.set_look_vertical = return_nil
|
||||||
|
|
||||||
|
--self.get_look_pitch`: pitch in radians - Deprecated as broken. Use `get_look_vertical`
|
||||||
|
--self.get_look_yaw`: yaw in radians - Deprecated as broken. Use `get_look_horizontal`
|
||||||
|
--self.set_look_pitch(radians)`: sets look pitch - Deprecated. Use `set_look_vertical`.
|
||||||
|
--self.set_look_yaw(radians)`: sets look yaw - Deprecated. Use `set_look_horizontal`.
|
||||||
|
self.get_breath = return_value(10)
|
||||||
|
self.set_breath = return_nil
|
||||||
|
self.get_attribute = return_nil
|
||||||
|
self.set_attribute = return_nil
|
||||||
|
|
||||||
|
self.set_inventory_formspec = return_nil
|
||||||
|
self.get_inventory_formspec = return_empty_string
|
||||||
|
self.get_player_control = return_value({jump=false, right=false, left=false, LMB=false, RMB=false, sneak=false, aux1=false, down=false, up=false} )
|
||||||
|
self.get_player_control_bits = return_zero
|
||||||
|
|
||||||
|
self.set_physics_override = return_nil
|
||||||
|
self.get_physics_override = return_value({speed = 1, jump = 1, gravity = 1, sneak = true, sneak_glitch = false, new_move = true,})
|
||||||
|
|
||||||
|
|
||||||
|
self.hud_add = return_nil
|
||||||
|
self.hud_remove = return_nil
|
||||||
|
self.hud_change = return_nil
|
||||||
|
self.hud_get = return_nil -- possibly important return value?
|
||||||
|
self.hud_set_flags = return_nil
|
||||||
|
self.hud_get_flags = return_value({ hotbar=true, healthbar=true, crosshair=true, wielditem=true, breathbar=true, minimap=true })
|
||||||
|
self.hud_set_hotbar_itemcount = return_nil
|
||||||
|
self.hud_get_hotbar_itemcount = return_zero
|
||||||
|
self.hud_set_hotbar_image = return_nil
|
||||||
|
self.hud_get_hotbar_image = return_empty_string
|
||||||
|
self.hud_set_hotbar_selected_image = return_nil
|
||||||
|
self.hud_get_hotbar_selected_image = return_empty_string
|
||||||
|
self.set_sky = return_nil
|
||||||
|
self.get_sky = return_empty_table -- may need members on this table
|
||||||
|
|
||||||
|
self.set_clouds = return_nil
|
||||||
|
self.get_clouds = return_value({density = 0, color = "#fff0f0e5", ambient = "#000000", height = 120, thickness = 16, speed = {x=0, y=-2}})
|
||||||
|
|
||||||
|
self.override_day_night_ratio = return_nil
|
||||||
|
self.get_day_night_ratio = return_nil
|
||||||
|
|
||||||
|
self.set_local_animation = return_nil
|
||||||
|
self.get_local_animation = return_empty_table
|
||||||
|
|
||||||
|
self.set_eye_offset = return_nil
|
||||||
|
self.get_eye_offset = return_value({x=0,y=0,z=0},{x=0,y=0,z=0})
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
@ -327,6 +327,11 @@ function DigtronLayout.write_layout_image(self, player)
|
|||||||
|
|
||||||
local dug_nodes = {}
|
local dug_nodes = {}
|
||||||
local placed_nodes = {}
|
local placed_nodes = {}
|
||||||
|
|
||||||
|
-- fake_player will be passed to callbacks to prevent actual player from "taking the blame" for this action.
|
||||||
|
-- For example, the hunger mod shouldn't be making the player hungry when he moves Digtron.
|
||||||
|
digtron.fake_player:update(self.controller, player:get_player_name())
|
||||||
|
-- note that the actual player is still passed to the per-node after_place_node and after_dig_node, should they exist.
|
||||||
|
|
||||||
-- destroy the old digtron
|
-- destroy the old digtron
|
||||||
local oldpos, _ = self.old_pos_pointset:pop()
|
local oldpos, _ = self.old_pos_pointset:pop()
|
||||||
@ -357,18 +362,11 @@ function DigtronLayout.write_layout_image(self, player)
|
|||||||
|
|
||||||
minetest.log("action", string.format("%s removes Digtron component %s at (%d, %d, %d)", player:get_player_name(), old_node.name, old_pos.x, old_pos.y, old_pos.z))
|
minetest.log("action", string.format("%s removes Digtron component %s at (%d, %d, %d)", player:get_player_name(), old_node.name, old_pos.x, old_pos.y, old_pos.z))
|
||||||
|
|
||||||
if modpath_awards then
|
|
||||||
-- We're about to tell the awards mod that we're digging a node, but we
|
|
||||||
-- don't want it to count toward any actual awards. Pre-decrement.
|
|
||||||
local data = awards.players[player:get_player_name()]
|
|
||||||
awards.increment_item_counter(data, "count", old_node.name, -1)
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, callback in ipairs(minetest.registered_on_dignodes) do
|
for _, callback in ipairs(minetest.registered_on_dignodes) do
|
||||||
-- Copy pos and node because callback can modify them
|
-- Copy pos and node because callback can modify them
|
||||||
local pos_copy = {x=old_pos.x, y=old_pos.y, z=old_pos.z}
|
local pos_copy = {x=old_pos.x, y=old_pos.y, z=old_pos.z}
|
||||||
local oldnode_copy = {name=old_node.name, param1=old_node.param1, param2=old_node.param2}
|
local oldnode_copy = {name=old_node.name, param1=old_node.param1, param2=old_node.param2}
|
||||||
callback(pos_copy, oldnode_copy, player)
|
callback(pos_copy, oldnode_copy, digtron.fake_player)
|
||||||
end
|
end
|
||||||
|
|
||||||
local old_def = minetest.registered_nodes[old_node.name]
|
local old_def = minetest.registered_nodes[old_node.name]
|
||||||
@ -384,19 +382,12 @@ function DigtronLayout.write_layout_image(self, player)
|
|||||||
|
|
||||||
minetest.log("action", string.format("%s adds Digtron component %s at (%d, %d, %d)", player:get_player_name(), new_node.name, new_pos.x, new_pos.y, new_pos.z))
|
minetest.log("action", string.format("%s adds Digtron component %s at (%d, %d, %d)", player:get_player_name(), new_node.name, new_pos.x, new_pos.y, new_pos.z))
|
||||||
|
|
||||||
if modpath_awards then
|
|
||||||
-- We're about to tell the awards mod that we're placing a node, but we
|
|
||||||
-- don't want it to count toward any actual awards. Pre-decrement.
|
|
||||||
local data = awards.players[player:get_player_name()]
|
|
||||||
awards.increment_item_counter(data, "place", new_node.name, -1)
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, callback in ipairs(minetest.registered_on_placenodes) do
|
for _, callback in ipairs(minetest.registered_on_placenodes) do
|
||||||
-- Copy pos and node because callback can modify them
|
-- Copy pos and node because callback can modify them
|
||||||
local pos_copy = {x=new_pos.x, y=new_pos.y, z=new_pos.z}
|
local pos_copy = {x=new_pos.x, y=new_pos.y, z=new_pos.z}
|
||||||
local oldnode_copy = {name=old_node.name, param1=old_node.param1, param2=old_node.param2}
|
local oldnode_copy = {name=old_node.name, param1=old_node.param1, param2=old_node.param2}
|
||||||
local newnode_copy = {name=new_node.name, param1=new_node.param1, param2=new_node.param2}
|
local newnode_copy = {name=new_node.name, param1=new_node.param1, param2=new_node.param2}
|
||||||
callback(pos_copy, newnode_copy, player, oldnode_copy)
|
callback(pos_copy, newnode_copy, digtron.fake_player, oldnode_copy)
|
||||||
end
|
end
|
||||||
|
|
||||||
local new_def = minetest.registered_nodes[new_node.name]
|
local new_def = minetest.registered_nodes[new_node.name]
|
||||||
|
20
init.lua
20
init.lua
@ -20,8 +20,28 @@ digtron.builder_read_item_substitutions = {
|
|||||||
["farming:desert_sand_soil_wet"] = "default:desert_sand",
|
["farming:desert_sand_soil_wet"] = "default:desert_sand",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Finally, items belonging to group "digtron_on_place" will have their on_place methods called.
|
||||||
|
|
||||||
local digtron_modpath = minetest.get_modpath( "digtron" )
|
local digtron_modpath = minetest.get_modpath( "digtron" )
|
||||||
|
|
||||||
|
dofile( digtron_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.
|
||||||
|
|
||||||
dofile( digtron_modpath .. "/config.lua" )
|
dofile( digtron_modpath .. "/config.lua" )
|
||||||
dofile( digtron_modpath .. "/util.lua" )
|
dofile( digtron_modpath .. "/util.lua" )
|
||||||
dofile( digtron_modpath .. "/doc.lua" )
|
dofile( digtron_modpath .. "/doc.lua" )
|
||||||
|
@ -32,8 +32,18 @@ local function has_prefix(str, prefix)
|
|||||||
return str:sub(1, string.len(prefix)) == prefix
|
return str:sub(1, string.len(prefix)) == prefix
|
||||||
end
|
end
|
||||||
|
|
||||||
local function blacklisted_on_place(item_name)
|
local function whitelisted_on_place(item_name)
|
||||||
if has_prefix(item_name, "stairs:slab_") then return true end
|
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
|
end
|
||||||
|
|
||||||
local function copy_pointed_thing(pointed_thing)
|
local function copy_pointed_thing(pointed_thing)
|
||||||
@ -77,7 +87,7 @@ digtron.item_place_node = function(itemstack, placer, place_to, param2)
|
|||||||
pointed_thing.under = {x=place_to.x, y=place_to.y - 1, 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.
|
-- Handle node-specific on_place calls as best we can.
|
||||||
if def.on_place and def.on_place ~= minetest.nodedef_default.on_place and not blacklisted_on_place(itemstack:get_name()) then
|
if def.on_place and def.on_place ~= minetest.nodedef_default.on_place and whitelisted_on_place(itemstack:get_name()) then
|
||||||
if def.paramtype2 == "facedir" then
|
if def.paramtype2 == "facedir" then
|
||||||
pointed_thing.under = vector.add(place_to, minetest.facedir_to_dir(param2))
|
pointed_thing.under = vector.add(place_to, minetest.facedir_to_dir(param2))
|
||||||
elseif def.paramtype2 == "wallmounted" then
|
elseif def.paramtype2 == "wallmounted" then
|
||||||
@ -128,7 +138,7 @@ digtron.item_place_node = function(itemstack, placer, place_to, param2)
|
|||||||
|
|
||||||
local take_item = true
|
local take_item = true
|
||||||
|
|
||||||
-- Run callback
|
-- Run callback, using genuine player for per-node definition.
|
||||||
if def.after_place_node then
|
if def.after_place_node then
|
||||||
-- Deepcopy place_to and pointed_thing because callback can modify it
|
-- 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 place_to_copy = {x=place_to.x, y=place_to.y, z=place_to.z}
|
||||||
@ -139,7 +149,10 @@ digtron.item_place_node = function(itemstack, placer, place_to, param2)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Run script hook
|
-- 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
|
local _, callback
|
||||||
for _, callback in ipairs(minetest.registered_on_placenodes) do
|
for _, callback in ipairs(minetest.registered_on_placenodes) do
|
||||||
-- Deepcopy pos, node and pointed_thing because callback can modify them
|
-- Deepcopy pos, node and pointed_thing because callback can modify them
|
||||||
@ -147,7 +160,7 @@ digtron.item_place_node = function(itemstack, placer, place_to, param2)
|
|||||||
local newnode_copy = {name=newnode.name, param1=newnode.param1, param2=newnode.param2}
|
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 oldnode_copy = {name=oldnode.name, param1=oldnode.param1, param2=oldnode.param2}
|
||||||
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
|
local pointed_thing_copy = copy_pointed_thing(pointed_thing)
|
||||||
if callback(place_to_copy, newnode_copy, placer, oldnode_copy, itemstack, pointed_thing_copy) then
|
if callback(place_to_copy, newnode_copy, digtron.fake_player, oldnode_copy, itemstack, pointed_thing_copy) then
|
||||||
take_item = false
|
take_item = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user