Finish farwand implementation

This commit is contained in:
Starbeamrainbowlabs 2020-06-13 14:23:14 +01:00
parent 6f20b31763
commit fbf2b894e5
Signed by: sbrl
GPG key ID: 1BE5172E637709C2
7 changed files with 196 additions and 20 deletions

View file

@ -7,3 +7,9 @@ end
function worldeditadditions.vector.lengthsquared(v) function worldeditadditions.vector.lengthsquared(v)
return v.x*v.x + v.y*v.y + v.z*v.z return v.x*v.x + v.y*v.y + v.z*v.z
end end
function worldeditadditions.vector.floor(v)
v.x = math.floor(v.x)
v.y = math.floor(v.y)
v.z = math.floor(v.z)
end

View file

@ -65,10 +65,14 @@ end
-- @param id number The content/node id to check. -- @param id number The content/node id to check.
-- @return bool Whether the given node/content id is a liquid-ish node or not. -- @return bool Whether the given node/content id is a liquid-ish node or not.
function worldeditadditions.is_liquidlike(id) function worldeditadditions.is_liquidlike(id)
print("[is_liquidlike]")
if id == node_id_ignore then return false end if id == node_id_ignore then return false end
if not minetest.registered_nodes[id] then return false end
local liquidtype = minetest.registered_nodes[id].liquidtype local node_name = minetest.get_name_from_content_id(id)
if node_name == nil or not minetest.registered_nodes[node_name] then return false end
local liquidtype = minetest.registered_nodes[node_name].liquidtype
print("[is_liquidlike]", "id", id, "liquidtype", liquidtype)
if liquidtype == nil or liquidtype == "none" then return false end if liquidtype == nil or liquidtype == "none" then return false end
-- If it's not none, then it has to be a liquid as the only other values are source and flowing -- If it's not none, then it has to be a liquid as the only other values are source and flowing

View file

@ -14,32 +14,53 @@ function worldeditadditions.raycast(player, maxdist, skip_liquid)
local player_pos = player:getpos() local player_pos = player:getpos()
player_pos.y = player_pos.y + 1.5 -- Calculate from the eye position player_pos.y = player_pos.y + 1.5 -- Calculate from the eye position
local divisor = 5
for i = 1, maxdist do for i = 1, maxdist do
local j = i / 10 local j = i / divisor
cur_pos.x = (look_dir.x*j) + player_pos.x cur_pos.x = (look_dir.x*j) + player_pos.x
cur_pos.y = (look_dir.y*j) + player_pos.y cur_pos.y = (look_dir.y*j) + player_pos.y
cur_pos.z = (look_dir.z*j) + player_pos.z cur_pos.z = (look_dir.z*j) + player_pos.z
local found_node = false
local node = minetest.get_node_or_nil(cur_pos) local node_pos = {
if node ~= nil then x = math.floor(0.5+cur_pos.x),
local node_id = minetest.get_content_id(node.name) y = math.floor(0.5+cur_pos.y),
local is_air = worldeditadditions.is_airlike(node_id) z = math.floor(0.5+cur_pos.z)
}
-- Don't bother if this is the same position we were looking at before
if not (node_pos.x == math.floor(0.5+look_dir.x*(j-divisor))
and node_pos.y == math.floor(0.5+look_dir.y*(j-divisor))
and node_pos.z == math.floor(0.5+look_dir.z*(j-divisor))) then
-- ignore = unloaded chunks, as far as I can tell local found_node = false
if node_id == node_id_ignore then
return nil
end
if is_air == false then local node = minetest.get_node_or_nil(node_pos)
if skip_liquid == true then if node ~= nil then
return cur_pos, node_id local node_id = minetest.get_content_id(node.name)
elseif worldeditadditions.is_liquidlike(node_id) == true then local is_air = worldeditadditions.is_airlike(node_id)
return cur_pos, node_id print("[raycast] Scanning "..worldeditadditions.vector.tostring(cur_pos)..", i: "..i..", j: "..j..", found", node.name, "is_air", is_air)
-- ignore = unloaded chunks, as far as I can tell
if node_id == node_id_ignore then
print("[raycast] found ignore, returning nil")
return nil
end
if is_air == false then
if skip_liquid == false then
return node_pos, node_id
else
local is_liquid = worldeditadditions.is_liquidlike(node_id)
print("[raycast] is_liquid ", is_liquid)
if is_liquid == false then
return node_pos, node_id
end
end
end end
end end
end end
end end

View file

@ -1,3 +1,9 @@
worldeditadditions.farwand = {
player_data = {}
}
local modpath = minetest.get_modpath("worldeditadditions_farwand") local modpath = minetest.get_modpath("worldeditadditions_farwand")
dofile(modpath.."/lib/farwand.lua") dofile(modpath.."/lib/farwand.lua")
dofile(modpath.."/lib/chatcommand.lua")
dofile(modpath.."/lib/settings.lua")

View file

@ -0,0 +1,61 @@
local farwand = worldeditadditions.farwand -- Convenience shurtcut
local function parse_params_farwand(params_text)
if params_text == nil then
return false, "Can't parse nil value"
end
local parts = worldeditadditions.split(params_text, "%s+", false)
local key = nil
local value = nil
if #parts >= 1 then
key = parts[1]
end
if #parts >= 2 then
value = parts[2]
end
return true, key, value
end
minetest.register_chatcommand("/farwand", {
params = "skip_liquid (true|false) | maxdist <number>",
description = "Configures your worldeditadditions farwand tool on a per-player basis. skip_liquid configures whether liquids will be skipped when raycasting. maxdist configues the maximum distance to raycast looking for a suitable node (default: 1000, but while higher values mean that it will search further, it's not an exact number of nodes that will be searched)",
privs = { worldedit = true },
func = function(name, params_text)
if name == nil then return end
local success, key, value = parse_params_farwand(params_text)
print("[/farwand] ", success, key, value)
if success == false then
worldedit.player_notify(name, key)
return
end
if key == "" then
worldedit.player_notify(name, "Current settings:\n"
.."\tskip_liquid\t"..tostring(farwand.setting_get(name, "skip_liquid")).."\n"
.."\tmaxdist\t"..tostring(farwand.setting_get(name, "maxdist")).."\n"
)
return
end
if key == "skip_liquid" then
local skip_liquid = false
if value == "true" then skip_liquid = true end
farwand.setting_set(name, "skip_liquid", skip_liquid)
worldedit.player_notify(name, "Set skip_liquid to "..tostring(skip_liquid)..".")
elseif key == "maxdist" then
local maxdist = tonumber(value)
if maxdist == nil then
worldedit.player_notify(name, "Invalid maxdist '"..value.."' (expected number).")
return
end
farwand.setting_set(name, "maxdist", maxdist)
worldedit.player_notify(name, "Set maxdist to "..tostring(maxdist)..".")
else
worldedit.player_notify(name, "Unknown key '"..key.."' (valid values: skip_liquid, maxdist).")
return
end
end
})

View file

@ -1,20 +1,65 @@
local function set_pos1(name, pos)
if pos ~= nil then
print("[set_pos1]", name, "("..pos.x..", "..pos.y..", "..pos.z..")")
worldedit.pos1[name] = pos
worldedit.mark_pos1(name)
else
print("[set_pos1]", name, "nil")
end
end
local function set_pos2(name, pos)
if pos ~= nil then
print("[set_pos2]", name, "("..pos.x..", "..pos.y..", "..pos.z..")")
worldedit.pos2[name] = pos
worldedit.mark_pos2(name)
else
print("[set_pos2]", name, "nil")
end
end
local function do_raycast(player)
if player == nil then return nil end
local player_name = player:get_player_name()
if worldeditadditions.farwand.player_data[player_name] == nil then
worldeditadditions.farwand.player_data[player_name] = { maxdist = 1000, skip_liquid = true }
end
local looking_pos, node_id = worldeditadditions.raycast(
player,
worldeditadditions.farwand.player_data[player_name].maxdist,
worldeditadditions.farwand.player_data[player_name].skip_liquid
)
return looking_pos, node_id
end
minetest.register_tool(":worldeditadditions:farwand", { minetest.register_tool(":worldeditadditions:farwand", {
description = "WorldEditAdditions far-reaching wand", description = "WorldEditAdditions far-reaching wand",
inventory_image = "worldeditadditions_farwand.png", inventory_image = "worldeditadditions_farwand.png",
on_place = function(itemstack, player, pointed_thing) on_place = function(itemstack, player, pointed_thing)
print("[farwand] on_place", player:get_player_name()) local name = player:get_player_name()
print("[farwand] on_place", name)
-- Right click when pointing at something -- Right click when pointing at something
-- Pointed thing: https://rubenwardy.com/minetest_modding_book/lua_api.html#pointed_thing
local looking_pos, node_id = do_raycast(player)
set_pos2(name, looking_pos)
end, end,
on_use = function(itemstack, player, pointed_thing) on_use = function(itemstack, player, pointed_thing)
print("[farwand] on_use", player:get_player_name()) local name = player:get_player_name()
print("[farwand] on_use", name)
local looking_pos, node_id = do_raycast(player)
set_pos1(name, looking_pos)
-- Left click when pointing at something or nothing -- Left click when pointing at something or nothing
end, end,
on_secondary_use = function(itemstack, player, pointed_thing) on_secondary_use = function(itemstack, player, pointed_thing)
local name = player:get_player_name()
-- Right click when pointing at nothing -- Right click when pointing at nothing
print("[farwand] on_secondary_use", name)
print("[farwand] on_secondary_use", player:get_player_name()) local looking_pos, node_id = do_raycast(player)
set_pos2(name, looking_pos)
end end
}) })

View file

@ -0,0 +1,33 @@
--- If the settings object for the given player name doesn't exist, it is created.
-- @param name The name of the player to ensure has a settings object.
local function settings_init(name)
if worldeditadditions.farwand.player_data[name] == nil then
print("[settings_init] ", worldeditadditions.farwand.player_data)
worldeditadditions.farwand.player_data[name] = {
maxdist = 1000,
skip_liquid = true
}
end
end
--- Gets a given farwand setting for the given player name.
-- @param string name The name of the player to get the setting for.
-- @param string setting_name The name of the setting to fetch.
-- @return any The value of the setting.
function worldeditadditions.farwand.setting_get(name, setting_name)
if setting_name == nil then return nil end
settings_init(name)
return worldeditadditions.farwand.player_data[name][setting_name]
end
--- Sets a given farwand setting for the given player name to the given value.
-- @param string name The name of the player to set the setting for.
-- @param string setting_name The name of the setting to set.
-- @param any setting_value The value to set the setting to.
-- @return bool Whether setting the setting was successful or not.
function worldeditadditions.farwand.setting_set(name, setting_name, setting_value)
if setting_name == nil then return false end
settings_init(name)
worldeditadditions.farwand.player_data[name][setting_name] = setting_value
return true
end