Update walking_light mod to Git commit 919f310...

https://github.com/AntumMT/mod-walking_light/tree/919f310
master
Jordan Irwin 2021-06-24 17:51:00 -07:00
parent a36b6cfefe
commit eec8e98345
14 changed files with 719 additions and 714 deletions

View File

@ -61,7 +61,7 @@ The game includes the mods from the default [minetest_game](https://github.com/m
* lighting/
* [glow][] ([GPL][lic.gpl2.0]) -- version: [4c015a0 Git][ver.glow] *2019-02-05*
* [ilights][] ([LGPL][lic.lgpl3.0]) -- version: [2021-02-25-01][ver.ilights] ([patched][patch.ilights])
* walking_light ([petermalone fork][walking_light]) ([WTFPL / CC BY-SA][lic.walking_light]) -- version: [766ef0f Git][ver.walking_light] *2019-11-09* ([patched][patch.walking_light])
* [walking_light][] ([WTFPL / CC BY-SA][lic.walking_light]) -- version: [919f310 Git][ver.walking_light] *2021-06-24*
* materials/
* [amber][] ([LGPL][lic.lgpl2.1]) -- version: [56627fa Git][ver.amber] *2017-10-29* ([patched][patch.amber])
* [basic_materials][] ([LGPL][lic.lgpl3.0]) -- version: [2021-01-30][ver.basic_materials]
@ -380,7 +380,7 @@ The game includes the mods from the default [minetest_game](https://github.com/m
[unifieddyes]: https://forum.minetest.net/viewtopic.php?t=2178
[vines]: https://forum.minetest.net/viewtopic.php?f=11&t=2344
[waffles]: https://forum.minetest.net/viewtopic.php?t=16669
[walking_light]: https://github.com/petermaloney/walking_light
[walking_light]: https://forum.minetest.net/viewtopic.php?t=2621
[wardrobe]: https://github.com/AntumMT/mod-wardrobe
[wardrobe.old]: https://forum.minetest.net/viewtopic.php?t=9680
[wdata]: https://forum.minetest.net/viewtopic.php?t=26804
@ -632,7 +632,7 @@ The game includes the mods from the default [minetest_game](https://github.com/m
[ver.tree_monster]: https://github.com/AntumMT/mod-mob_tree_monster/tree/f2977ff
[ver.unifieddyes]: https://gitlab.com/VanessaE/unifieddyes/tags/2021-03-26-1
[ver.waffles]: https://github.com/GreenXenith/waffles/tree/15bcdce
[ver.walking_light]: https://github.com/petermaloney/walking_light/tree/766ef0f
[ver.walking_light]: https://github.com/AntumMT/mod-walking_light/tree/919f310
[ver.wardrobe]: https://github.com/AntumMT/mod-wardrobe/tree/0500a78
[ver.wdata]: https://github.com/AntumMT/mod-wdata/releases/tag/v1.1
[ver.whinny]: https://github.com/AntumMT/mod-whinny/tree/32f2d9f
@ -680,5 +680,4 @@ The game includes the mods from the default [minetest_game](https://github.com/m
[patch.throwing]: https://github.com/AntumMT/mod-throwing/tree/b33ffde
[patch.trash_can]: https://github.com/AntumMT/mod-trash_can/tree/5a92bf4
[patch.unifieddyes]: https://github.com/AntumMT/mod-unifieddyes/tree/3013964
[patch.walking_light]: https://github.com/AntumMT/mod-walking_light/tree/b482369
[patch.windmill]: https://github.com/AntumMT/mod-windmill/tree/7756ab4

View File

@ -0,0 +1,4 @@
TODO:
- clean up
- add localization support

View File

@ -0,0 +1,531 @@
-- list of all players seen by core.register_on_joinplayer
local players = {}
-- all player positions last time light was updated: {player_name : {x, y, z}}
local player_positions = {}
-- all light positions of light that currently is created {player_name : {i: {x, y, z}}
local light_positions = {}
-- last item seen wielded by players
local last_wielded = {}
-- toggles debug mode
local walking_light_debug = false
-- name of light node, changed by toggling debug mode
local walking_light_node = nil
function walking_light.set_debug(enabled)
walking_light_debug = enabled
end
-- list of items that use walking light
local light_items = {
"default:torch",
"walking_light:megatorch",
}
local light_armor = {}
function walking_light.register_item(item)
for _, li in ipairs(light_items) do
if item == li then
core.log("warning", "[walking_light] \"" .. item .. "\" is already light item.")
return
end
end
table.insert(light_items, item)
end
walking_light.addLightItem = walking_light.register_item -- backward compat
function walking_light.register_armor(iname, litem)
if litem == nil then litem = true end
for _, a in ipairs(light_armor) do
if iname == a then
core.log("warning", "[walking_light] \"" .. iname .. "\" is already light armor.")
end
end
table.insert(light_armor, iname)
if litem then walking_light.register_item(iname) end
end
function walking_light.get_light_items()
return light_items
end
walking_light.getLightItems = walking_light.get_light_items -- backward compat
function walking_light.register_tool(tool)
walking_light.log("warning", "\"walking_light.register_tool\" method is deprecated")
local item, default, definition
item = "walking_light:" .. tool .. "_mese"
default = "default:" .. tool .. "_mese"
definition = table.copy(core.registered_items[default])
definition.description = definition.description .. " with light"
definition.inventory_image = "walking_light_mese" .. tool .. ".png"
core.register_tool(item, definition)
core.register_craft({
output = item,
recipe = {
{"default:torch"},
{ default },
}
})
walking_light.register_item(item)
end
-- from http://lua-users.org/wiki/IteratorsTutorial
-- useful for removing things from a table because removing from the middle makes it skip elements otherwise
local function ripairs(t)
local function ripairs_it(t, i)
i = i-1
local v = t[i]
if v == nil then return v end
return i, v
end
return ripairs_it, t, #t+1
end
-- formats a vector with shorter output than dump
local function dumppos(pos)
if pos == nil then
return "nil"
end
local x = "nil"
if pos.x then
x = pos.x
end
local y = "nil"
if pos.y then
y = pos.y
end
local z = "nil"
if pos.z then
z = pos.z
end
return "(" .. x .. "," .. y .. "," .. z .. ")"
end
-- formats a table containing vectors with shorter output than dump
local function dumppostable(t)
if t == nil then
return "nil"
end
if #t == 0 then
return "0{}"
end
ret = #t .. "{\n"
for i, pos in ipairs(t) do
ret = ret .. " " .. dumppos(pos) .. "\n"
end
ret = ret .. "}"
return ret
end
local function mt_get_node_or_nil(pos)
if pos == nil then
print("ERROR: walking_light.mt_get_node_or_nil(), pos is nil")
print(debug.traceback("Current Callstack:\n"))
return nil
end
local node = core.get_node_or_nil(pos)
if not node then
-- Load the map at pos and try again
core.get_voxel_manip():read_from_map(pos, pos)
node = core.get_node(pos)
end
-- If node.name is "ignore" here, the map probably isn't generated at pos.
return node
end
function mt_add_node(pos, sometable)
if pos == nil then
print("ERROR: walking_light.mt_add_node(), pos is nil")
print(debug.traceback("Current Callstack:\n"))
return nil
end
if sometable == nil then
print("ERROR: walking_light.mt_add_node(), sometable is nil")
print(debug.traceback("Current Callstack:\n"))
return nil
end
core.add_node(pos, sometable)
end
local function round(num)
return math.floor(num + 0.5)
end
local function poseq(pos1, pos2)
if pos1 == nil and pos2 == nil then
return true
end
if pos1 == nil or pos2 == nil then
return false
end
return pos1.x == pos2.x and pos1.y == pos2.y and pos1.z == pos2.z
end
-- return true if the player moved since last player_positions update
local function player_moved(player)
local player_name = player:get_player_name()
local pos = player:get_pos()
local rounded_pos = vector.round(pos)
local oldpos = player_positions[player_name]
if oldpos == nil or not poseq(rounded_pos, oldpos) then
-- if oldpos is nil, we assume they just logged in, so consider them moved
return true
end
return false
end
-- same as table.remove(t, remove_pos), but uses poseq instead of comparing references (does lua have comparator support, so this isn't needed?)
local function table_remove_pos(t, remove_pos)
for i, pos in ipairs(t) do
if poseq(pos, remove_pos) then
table.remove(t, i)
break
end
end
end
-- same as t[remove_pos], but uses poseq instead of comparing references (does lua have comparator support, so this isn't needed?)
local function table_contains_pos(t, remove_pos)
for i, pos in ipairs(t) do
if poseq(pos, remove_pos) then
return true
end
end
return false
end
-- same as table.insert(t, pos) but makes sure it is not duplicated
local function table_insert_pos(t, pos)
if not table_contains_pos( pos ) then
table.insert(t, pos)
end
end
local function is_light(node)
if node ~= nil and node ~= "ignore" and( node.name == "walking_light:light" or node.name == "walking_light:light_debug" ) then
return true
end
return false
end
-- removes light at the given position
-- player is optional
function remove_light(player, pos)
local player_name
if player then
player_name = player:get_player_name()
end
local node = mt_get_node_or_nil(pos)
if is_light(node) then
mt_add_node(pos, {type="node", name="air"})
if player_name then
table_remove_pos(light_positions[player_name], pos)
end
else
if node ~= nil then
print("WARNING: walking_light.remove_light(), pos = " .. dumppos(pos) .. ", tried to remove light but node was " .. node.name)
table_remove_pos(light_positions[player_name], pos)
else
print("WARNING: walking_light.remove_light(), pos = " .. dumppos(pos) .. ", tried to remove light but node was nil")
end
end
end
-- removes all light owned by a player
local function remove_light_player(player)
local player_name = player:get_player_name()
for i, old_pos in ripairs(light_positions[player_name]) do
if old_pos then
remove_light(player, old_pos)
end
end
end
local function can_add_light(pos)
local node = mt_get_node_or_nil(pos)
if node == nil or node == "ignore" then
-- if node is nil (unknown) or ignore (not generated), then we don't do anything.
return false
elseif node.name == "air" then
return true
elseif is_light(node) then
return true
end
return false
end
-- old function returns pos instead of table, for only one position
local function pick_light_position_regular(player, pos)
if can_add_light(pos) then
return {pos}
end
local pos2
-- if pos is not possible, try the old player position first, to make it more likely that it has a line of sight
local player_name = player:get_player_name()
local oldplayerpos = player_positions[player_name]
if oldplayerpos and can_add_light( vector.new(oldplayerpos.x, oldplayerpos.y + 1, oldplayerpos.z) ) then
return oldplayerpos
end
-- if not, try all positions around the pos
pos2 = vector.new(pos.x + 1, pos.y, pos.z)
if can_add_light( pos2 ) then
return {pos2}
end
pos2 = vector.new(pos.x - 1, pos.y, pos.z)
if can_add_light( pos2 ) then
return {pos2}
end
pos2 = vector.new(pos.x, pos.y, pos.z + 1)
if can_add_light( pos2 ) then
return {pos2}
end
pos2 = vector.new(pos.x, pos.y, pos.z - 1)
if can_add_light( pos2 ) then
return {pos2}
end
pos2 = vector.new(pos.x, pos.y + 1, pos.z)
if can_add_light( pos2 ) then
return {pos2}
end
pos2 = vector.new(pos.x, pos.y - 1, pos.z)
if can_add_light( pos2 ) then
return {pos2}
end
return nil
end
-- new function, returns table
local function pick_light_position_radius(player, pos, ret, radius)
local pos2
local step = 4
local unstep = 1/step
for x = pos.x - radius, pos.x + radius, step do
for y = pos.y - radius, pos.y + radius, step do
for z = pos.z - radius, pos.z + radius, step do
pos2 = vector.new(round(x*unstep)*step, round(y*unstep)*step, round(z*unstep)*step)
distance = math.sqrt(math.pow(pos.x - x, 2) + math.pow(pos.y - y, 2) + math.pow(pos.z - z, 2))
if distance <= radius and can_add_light( pos2 ) then
table.insert(ret, pos2)
end
end
end
end
return ret
end
local function pick_light_position_mega(player, pos)
local ret = {}
if can_add_light(pos) then
table.insert(ret, pos)
end
pick_light_position_radius(player, pos, ret, 10)
return ret
end
local function pick_light_position(player, pos, light_item)
if light_item == "walking_light:megatorch" then
return pick_light_position_mega(player, pos)
end
return pick_light_position_regular(player, pos)
end
-- adds light at the given position
local function add_light(player, pos)
local player_name = player:get_player_name()
local node = mt_get_node_or_nil(pos)
if node == nil or node == "ignore" then
-- don't do anything for nil (non-loaded) or ignore (non-generated) blocks, so we don't want to overwrite anything there
return false
elseif node.name == "air" then
-- when the node that is already there is air, add light
mt_add_node(pos, {type="node", name=walking_light_node})
if not table_contains_pos(light_positions[player_name], pos) then
table_insert_pos(light_positions[player_name], pos)
end
return true
elseif is_light(node) then
-- no point in adding light where it is already, but we should assign it to the player so it gets removed (in case it has no player)
if not table_contains_pos(light_positions[player_name], pos) then
table_insert_pos(light_positions[player_name], pos)
end
return true
end
return false
end
-- updates all the light around the player, depending on what they are wielding
local function update_light_player(player)
-- if there is no player, there can be no update
if not player then
return
end
-- figure out if they wield light; this will be nil if not
local wielded_item = walking_light.get_wielded_light_item(player)
local player_name = player:get_player_name()
local pos = player:get_pos()
local rounded_pos = vector.round(pos)
-- check for a nil node where the player is; if it is nil, we assume the block is not loaded, so we return without updating player_positions
-- that way, it should add light next step
local node = mt_get_node_or_nil(rounded_pos)
if node == nil or node == "ignore" then
return
end
if not player_moved(player) and wielded_item == last_wielded[player_name] then
-- no update needed if the wiedled light item is the same as before (including nil), and the player didn't move
return
end
last_wielded[player_name] = wielded_item;
local wantlightpos = nil
local wantpos = vector.new(rounded_pos.x, rounded_pos.y + 1, rounded_pos.z)
if wielded_item then
-- decide where light should be
wantlightpos = pick_light_position(player, wantpos, wielded_item)
end
if wielded_item and wantlightpos then
-- add light that isn't already there
for i, newpos in ipairs(wantlightpos) do
add_light(player, newpos)
end
end
-- go through all light owned by the player to remove all but what should be kept
for i, oldlightpos in ripairs(light_positions[player_name]) do
if not wantlightpos or oldlightpos and oldlightpos.x and not table_contains_pos(wantlightpos, oldlightpos) then
remove_light(player, oldlightpos)
end
end
player_positions[player_name] = vector.round(pos)
end
local function update_light_all()
-- go through all players to check
for i, player_name in ipairs(players) do
local player = core.get_player_by_name(player_name)
update_light_player(player)
end
end
-- return true if item is a light item
function walking_light.is_light_item(item)
for _, li in ipairs(light_items) do
if item == li then
return true
end
end
return false
end
-- returns a string, the name of the item found that is a light item
function walking_light.get_wielded_light_item(player)
local wielded_item = player:get_wielded_item():get_name()
if walking_light.is_light_item(wielded_item) then
return wielded_item
end
-- check equipped armor - requires unified_inventory maybe
if core.get_modpath("3d_armor") then
local player_name = player:get_player_name()
if player_name then
local armor_inv = core.get_inventory({type="detached", name=player_name.."_armor"})
if armor_inv then
-- FIXME: should be a more efficient method
for _, item_name in ipairs(light_armor) do
if armor_inv:contains_item("armor", ItemStack(item_name)) then
return item_name
end
end
end
end
end
return nil
end
-- return true if player is wielding a light item
function walking_light.wields_light(player)
return walking_light.get_wielded_light_item(player) ~= nil
end
core.register_on_joinplayer(function(player)
local player_name = player:get_player_name()
table.insert(players, player_name)
last_wielded[player_name] = walking_light.get_wielded_light_item(player)
local pos = player:get_pos()
player_positions[player_name] = nil
light_positions[player_name] = {}
update_light_player(player)
end)
core.register_on_leaveplayer(function(player)
local player_name = player:get_player_name()
for i, v in ipairs(players) do
if v == player_name then
table.remove(players, i)
end
end
last_wielded[player_name] = false
remove_light_player(player)
player_positions[player_name] = nil
end)
core.register_globalstep(function(dtime)
for i, player_name in ipairs(players) do
local player = core.get_player_by_name(player_name)
if player ~= nil then
update_light_player(player)
else
table.remove(players, i)
end
end
end)
function walking_light.update_node()
if walking_light_debug then
walking_light_node = "walking_light:light_debug"
else
walking_light_node = "walking_light:light"
end
end
walking_light.update_node()

View File

@ -0,0 +1,7 @@
v1.0
- forked from petermaloney @ Git commit 766ef0f ( https://github.com/petermaloney/walking_light/tree/766ef0f )
v0.7
----
- forked from walking_light v0.6 by Echo ( https://forum.minetest.net/viewtopic.php?t=2621 )

View File

@ -0,0 +1,60 @@
core.register_chatcommand("walking_light_clear_light", {
params = "<size>",
description = "Remove light nodes from the area",
func = function(name, param)
if not core.check_player_privs(name, {server=true}) then
return false, "You need the server privilege to use mapclearlight"
end
local pos = vector.round(core.get_player_by_name(name):get_pos())
local size = tonumber(param) or 40
for i, v in ipairs({"walking_light:light", "walking_light:light_debug"}) do
local point = core.find_node_near(pos, size/2, v)
while point do
remove_light(nil, point)
local oldpoint = point
point = core.find_node_near(pos, size/2, v)
if poseq(oldpoint, point) then
return false, "Failed... infinite loop detected"
end
end
end
return true, "Done."
end,
})
core.register_chatcommand("walking_light_add_light", {
params = "<size>",
description = "Add walking_light:light to a position, without a player owning it",
func = function(name, param)
if not core.check_player_privs(name, {server=true}) then
return false, "You need the server privilege to use mapaddlight"
end
local pos = vector.round(core.get_player_by_name(name):get_pos())
pos = vector.new(pos.x, pos.y + 1, pos.z)
if pos then
mt_add_node(pos, {type="node", name=walking_light_node})
end
return true, "Done."
end,
})
core.register_chatcommand("walking_light_debug", {
description = "Change to debug mode, so light blocks are visible.",
func = function(name, param)
if not core.check_player_privs(name, {server=true}) then
return false, "You need the server privilege to use walking_light_debug"
end
-- toggle debug mode
walking_light.set_debug(not walking_light_debug)
walking_light.update_node()
return true, "Done."
end,
})

View File

@ -1,716 +1,29 @@
-- list of all players seen by minetest.register_on_joinplayer
local players = {}
-- all player positions last time light was updated: {player_name : {x, y, z}}
local player_positions = {}
-- all light positions of light that currently is created {player_name : {i: {x, y, z}}
local light_positions = {}
-- last item seen wielded by players
local last_wielded = {}
-- toggles debug mode
local walking_light_debug = false
-- name of light node, changed by toggling debug mode
local walking_light_node = nil
-- initialize walking light
walking_light = {}
walking_light.modname = core.get_current_modname()
walking_light.modpath = core.get_modpath(walking_light.modname)
-- list of items that use walking light
local light_items = {
"default:torch", "walking_light:pick_mese",
"walking_light:helmet_diamond", "walking_light:megatorch",
"walking_light:helmet_gold",
function walking_light.log(lvl, msg)
if not msg then
msg = lvl
lvl = nil
end
msg = "[" .. walking_light.modname .. "] " .. msg
if not lvl then
core.log(msg)
else
core.log(lvl, msg)
end
end
local scripts = {
"api",
"chat",
"nodes",
}
function walking_light.addLightItem(item)
for I in pairs(light_items) do
if item == light_items[I] then
minetest.log("warning", "[walking_light] \"" .. item .. "\" is already light item.")
return
end
end
table.insert(light_items, -1, item)
for _, sc in ipairs(scripts) do
dofile(walking_light.modpath .. "/" .. sc .. ".lua")
end
function walking_light.getLightItems()
return light_items
end
function walking_light.register_tool(tool)
local item, default, definition
item = 'walking_light:' .. tool .. '_mese'
default = 'default:' .. tool .. '_mese'
definition = table.copy(minetest.registered_items[default])
definition.description = definition.description .. ' with light'
definition.inventory_image = 'walking_light_mese' .. tool .. '.png'
minetest.register_tool(item, definition)
minetest.register_craft({
output = item,
recipe = {
{'default:torch'},
{ default },
}
})
walking_light.addLightItem(item)
end
-- from http://lua-users.org/wiki/IteratorsTutorial
-- useful for removing things from a table because removing from the middle makes it skip elements otherwise
function ripairs(t)
local function ripairs_it(t,i)
i=i-1
local v=t[i]
if v==nil then return v end
return i,v
end
return ripairs_it, t, #t+1
end
-- formats a vector with shorter output than dump
local function dumppos(pos)
if pos == nil then
return "nil"
end
local x = "nil"
if pos.x then
x = pos.x
end
local y = "nil"
if pos.y then
y = pos.y
end
local z = "nil"
if pos.z then
z = pos.z
end
return "(" .. x .. "," .. y .. "," .. z .. ")"
end
-- formats a table containing vectors with shorter output than dump
local function dumppostable(t)
if t == nil then
return "nil"
end
if #t == 0 then
return "0{}"
end
ret = #t .. "{\n"
for i,pos in ipairs(t) do
ret = ret .. " " .. dumppos(pos) .. "\n"
end
ret = ret .. "}"
return ret
end
function mt_get_node_or_nil(pos)
if pos == nil then
print("ERROR: walking_light.mt_get_node_or_nil(), pos is nil")
print(debug.traceback("Current Callstack:\n"))
return nil
end
local node = minetest.get_node_or_nil(pos)
if not node then
-- Load the map at pos and try again
minetest.get_voxel_manip():read_from_map(pos, pos)
node = minetest.get_node(pos)
end
-- If node.name is "ignore" here, the map probably isn't generated at pos.
return node
end
function mt_add_node(pos, sometable)
if pos == nil then
print("ERROR: walking_light.mt_add_node(), pos is nil")
print(debug.traceback("Current Callstack:\n"))
return nil
end
if sometable == nil then
print("ERROR: walking_light.mt_add_node(), sometable is nil")
print(debug.traceback("Current Callstack:\n"))
return nil
end
minetest.add_node(pos,sometable)
end
function round(num)
return math.floor(num + 0.5)
end
local function poseq(pos1, pos2)
if pos1 == nil and pos2 == nil then
return true
end
if pos1 == nil or pos2 == nil then
return false
end
return pos1.x == pos2.x and pos1.y == pos2.y and pos1.z == pos2.z
end
-- return true if the player moved since last player_positions update
local function player_moved(player)
local player_name = player:get_player_name()
local pos = player:get_pos()
local rounded_pos = vector.round(pos)
local oldpos = player_positions[player_name]
if oldpos == nil or not poseq(rounded_pos, oldpos) then
-- if oldpos is nil, we assume they just logged in, so consider them moved
-- print("DEBUG: walking_light, player_moved(); moved = true; rounded_pos = " .. dumppos(rounded_pos) .. ", oldpos = " .. dumppos(oldpos))
return true
end
-- print("DEBUG: walking_light, player_moved(); moved = false; rounded_pos = " .. dumppos(rounded_pos) .. ", oldpos = " .. dumppos(oldpos))
return false
end
-- same as table.remove(t,remove_pos), but uses poseq instead of comparing references (does lua have comparator support, so this isn't needed?)
local function table_remove_pos(t, remove_pos)
-- local DEBUG_oldsize = #t
for i,pos in ipairs(t) do
if poseq(pos, remove_pos) then
table.remove(t, i)
break
end
end
-- local DEBUG_newsize = #t
-- print("DEBUG: walking_light.table_remove_pos(), oldsize = " .. DEBUG_oldsize .. ", newsize = " .. DEBUG_newsize)
end
-- same as t[remove_pos], but uses poseq instead of comparing references (does lua have comparator support, so this isn't needed?)
local function table_contains_pos(t, remove_pos)
for i,pos in ipairs(t) do
if poseq(pos, remove_pos) then
return true
end
end
return false
end
-- same as table.insert(t,pos) but makes sure it is not duplicated
local function table_insert_pos(t, pos)
if not table_contains_pos( pos ) then
table.insert(t, pos)
end
end
local function is_light(node)
if node ~= nil and node ~= "ignore" and( node.name == "walking_light:light" or node.name == "walking_light:light_debug" ) then
return true
end
return false
end
-- removes light at the given position
-- player is optional
local function remove_light(player, pos)
local player_name
if player then
player_name = player:get_player_name()
end
local node = mt_get_node_or_nil(pos)
if is_light(node) then
mt_add_node(pos,{type="node",name="air"})
if player_name then
table_remove_pos(light_positions[player_name], pos)
end
else
if node ~= nil then
print("WARNING: walking_light.remove_light(), pos = " .. dumppos(pos) .. ", tried to remove light but node was " .. node.name)
table_remove_pos(light_positions[player_name], pos)
else
print("WARNING: walking_light.remove_light(), pos = " .. dumppos(pos) .. ", tried to remove light but node was nil")
end
end
end
-- removes all light owned by a player
local function remove_light_player(player)
local player_name = player:get_player_name()
for i,old_pos in ripairs(light_positions[player_name]) do
if old_pos then
-- print("DEBUG: walking_light.remove_light_player(), removing old light; old_pos = " .. dumppos(old_pos))
remove_light(player, old_pos)
end
end
-- print("DEBUG: walking_light.remove_light_player(), done; light_positions = " .. dumppostable(light_positions[player_name]))
end
local function can_add_light(pos)
local node = mt_get_node_or_nil(pos)
if node == nil or node == "ignore" then
-- if node is nil (unknown) or ignore (not generated), then we don't do anything.
return false
elseif node.name == "air" then
-- print("walking_light can_add_light(), pos = " .. dumppos(pos) .. ", true")
return true
elseif is_light(node) then
-- print("walking_light can_add_light(), pos = " .. dumppos(pos) .. ", true")
return true
end
-- print("walking_light can_add_light(), pos = " .. dumppos(pos) .. ", false")
return false
end
-- old function returns pos instead of table, for only one position
local function pick_light_position_regular(player, pos)
if can_add_light(pos) then
return {pos}
end
local pos2
-- if pos is not possible, try the old player position first, to make it more likely that it has a line of sight
local player_name = player:get_player_name()
local oldplayerpos = player_positions[player_name]
if oldplayerpos and can_add_light( vector.new(oldplayerpos.x, oldplayerpos.y + 1, oldplayerpos.z) ) then
return oldplayerpos
end
-- if not, try all positions around the pos
pos2 = vector.new(pos.x + 1, pos.y, pos.z)
if can_add_light( pos2 ) then
return {pos2}
end
pos2 = vector.new(pos.x - 1, pos.y, pos.z)
if can_add_light( pos2 ) then
return {pos2}
end
pos2 = vector.new(pos.x, pos.y, pos.z + 1)
if can_add_light( pos2 ) then
return {pos2}
end
pos2 = vector.new(pos.x, pos.y, pos.z - 1)
if can_add_light( pos2 ) then
return {pos2}
end
pos2 = vector.new(pos.x, pos.y + 1, pos.z)
if can_add_light( pos2 ) then
return {pos2}
end
pos2 = vector.new(pos.x, pos.y - 1, pos.z)
if can_add_light( pos2 ) then
return {pos2}
end
return nil
end
-- new function, returns table
local function pick_light_position_radius(player, pos, ret, radius)
local pos2
local step = 4
local unstep = 1/step
for x = pos.x - radius, pos.x + radius, step do
for y = pos.y - radius, pos.y + radius, step do
for z = pos.z - radius, pos.z + radius, step do
pos2 = vector.new(round(x*unstep)*step, round(y*unstep)*step, round(z*unstep)*step)
distance = math.sqrt(math.pow(pos.x - x, 2) + math.pow(pos.y - y, 2) + math.pow(pos.z - z, 2))
if distance <= radius and can_add_light( pos2 ) then
table.insert(ret, pos2)
end
end
end
end
return ret
end
local function pick_light_position_mega(player, pos)
local ret = {}
if can_add_light(pos) then
table.insert(ret, pos)
end
pick_light_position_radius(player, pos, ret, 10)
return ret
end
local function pick_light_position(player, pos, light_item)
if light_item == "walking_light:megatorch" then
return pick_light_position_mega(player, pos)
end
return pick_light_position_regular(player, pos)
end
-- adds light at the given position
local function add_light(player, pos)
local player_name = player:get_player_name()
local node = mt_get_node_or_nil(pos)
if node == nil or node == "ignore" then
-- don't do anything for nil (non-loaded) or ignore (non-generated) blocks, so we don't want to overwrite anything there
-- print("DEBUG: walking_light.add_light(), node is nil, pos = " .. dumppos(pos))
return false
elseif node.name == "air" then
-- when the node that is already there is air, add light
mt_add_node(pos,{type="node",name=walking_light_node})
if not table_contains_pos(light_positions[player_name], pos) then
table_insert_pos(light_positions[player_name], pos)
end
-- if node then
-- print("DEBUG: add_light(), node.name = " .. node.name .. ", pos = " .. dumppos(pos))
-- else
-- print("DEBUG: add_light(), node.name = nil, pos = " .. dumppos(pos))
-- end
return true
elseif is_light(node) then
-- no point in adding light where it is already, but we should assign it to the player so it gets removed (in case it has no player)
-- print("DEBUG: add_light(), not adding; node.name = " .. node.name .. ", pos = " .. dumppos(pos))
if not table_contains_pos(light_positions[player_name], pos) then
table_insert_pos(light_positions[player_name], pos)
end
return true
end
-- print("DEBUG: add_light(), not adding; node.name = " .. node.name)
return false
end
-- updates all the light around the player, depending on what they are wielding
local function update_light_player(player)
-- if there is no player, there can be no update
if not player then
return
end
-- figure out if they wield light; this will be nil if not
local wielded_item = get_wielded_light_item(player)
local player_name = player:get_player_name()
local pos = player:get_pos()
local rounded_pos = vector.round(pos)
-- check for a nil node where the player is; if it is nil, we assume the block is not loaded, so we return without updating player_positions
-- that way, it should add light next step
local node = mt_get_node_or_nil(rounded_pos)
if node == nil or node == "ignore" then
return
end
if not player_moved(player) and wielded_item == last_wielded[player_name] then
-- no update needed if the wiedled light item is the same as before (including nil), and the player didn't move
return
end
last_wielded[player_name] = wielded_item;
local wantlightpos = nil
local wantpos = vector.new(rounded_pos.x, rounded_pos.y + 1, rounded_pos.z)
if wielded_item then
-- decide where light should be
wantlightpos = pick_light_position(player, wantpos, wielded_item)
-- print("DEBUG: walking_light update_light_player(); wantpos = " .. dumppos(wantpos) .. ", wantlightpos = " .. dumppos(wantlightpos))
end
if wielded_item and wantlightpos then
-- add light that isn't already there
for i,newpos in ipairs(wantlightpos) do
add_light(player, newpos)
end
end
-- go through all light owned by the player to remove all but what should be kept
for i,oldlightpos in ripairs(light_positions[player_name]) do
if not wantlightpos or oldlightpos and oldlightpos.x and not table_contains_pos(wantlightpos, oldlightpos) then
remove_light(player, oldlightpos)
end
end
player_positions[player_name] = vector.round(pos)
-- print("DEBUG: walking_light.update_light_player(): wantlightpos = " .. dumppostable(wantlightpos) .. ", light_positions = " .. dumppostable(light_positions[player_name]))
end
local function update_light_all()
-- go through all players to check
for i,player_name in ipairs(players) do
local player = minetest.get_player_by_name(player_name)
update_light_player(player)
end
end
-- return true if item is a light item
function is_light_item(item)
for I in pairs(light_items) do
if item == light_items[I] then
return true
end
end
return false
end
-- returns a string, the name of the item found that is a light item
function get_wielded_light_item(player)
local wielded_item = player:get_wielded_item():get_name()
if is_light_item(wielded_item) then
return wielded_item
end
-- check equipped armor - requires unified_inventory maybe
local player_name = player:get_player_name()
if player_name then
local armor_inv = minetest.get_inventory({type="detached", name=player_name.."_armor"})
if armor_inv then
-- print( dump(armor_inv:get_lists()) )
local item_name = "walking_light:helmet_diamond"
local stack = ItemStack(item_name)
if armor_inv:contains_item("armor", stack) then
return item_name
end
-- Gold helmet
local item_name = "walking_light:helmet_gold"
local stack = ItemStack(item_name)
if armor_inv:contains_item("armor", stack) then
return item_name
end
end
end
return nil
end
-- return true if player is wielding a light item
function wielded_light(player)
return get_wielded_light_item(player) ~= nil
end
minetest.register_on_joinplayer(function(player)
local player_name = player:get_player_name()
table.insert(players, player_name)
last_wielded[player_name] = get_wielded_light_item(player)
local pos = player:get_pos()
player_positions[player_name] = nil
light_positions[player_name] = {}
update_light_player(player)
end)
minetest.register_on_leaveplayer(function(player)
local player_name = player:get_player_name()
for i,v in ipairs(players) do
if v == player_name then
table.remove(players, i)
end
end
last_wielded[player_name] = false
remove_light_player(player)
player_positions[player_name]=nil
end)
minetest.register_globalstep(function(dtime)
for i,player_name in ipairs(players) do
local player = minetest.get_player_by_name(player_name)
if player ~= nil then
update_light_player(player)
else
table.remove(players, i)
end
end
end)
minetest.register_node("walking_light:light_debug", {
drawtype = "glasslike",
tiles = {"walking_light_debug.png"},
inventory_image = minetest.inventorycube("walking_light.png"),
paramtype = "light",
walkable = false,
is_ground_content = true,
sunlight_propagates = true,
light_source = 13,
selection_box = {
type = "fixed",
fixed = {0, 0, 0, 0, 0, 0},
},
})
minetest.register_node("walking_light:light", {
drawtype = "glasslike",
tiles = {"walking_light.png"},
inventory_image = minetest.inventorycube("walking_light.png"),
paramtype = "light",
walkable = false,
is_ground_content = true,
sunlight_propagates = true,
light_source = 13,
selection_box = {
type = "fixed",
fixed = {0, 0, 0, 0, 0, 0},
},
})
function update_walking_light_node()
if walking_light_debug then
walking_light_node = "walking_light:light_debug"
else
walking_light_node = "walking_light:light"
end
end
update_walking_light_node()
minetest.register_tool("walking_light:pick_mese", {
description = "Mese Pickaxe with light",
inventory_image = "walking_light_mesepick.png",
wield_image = "default_tool_mesepick.png",
tool_capabilities = {
full_punch_interval = 1.0,
max_drop_level=3,
groupcaps={
cracky={times={[1]=2.0, [2]=1.0, [3]=0.5}, uses=0, maxlevel=3},
crumbly={times={[1]=2.0, [2]=1.0, [3]=0.5}, uses=0, maxlevel=3},
snappy={times={[1]=2.0, [2]=1.0, [3]=0.5}, uses=0, maxlevel=3}
}
},
})
minetest.register_tool("walking_light:helmet_diamond", {
description = "Diamond Helmet with light",
inventory_image = "walking_light_inv_helmet_diamond.png",
wield_image = "3d_armor_inv_helmet_diamond.png",
groups = {armor_head=15, armor_heal=12, armor_use=100},
wear = 0,
})
minetest.register_node("walking_light:megatorch", {
description = "Megatorch",
drawtype = "torchlike",
tiles = {
{
name = "default_torch_on_floor_animated.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 3.0
},
},
{
name="default_torch_on_ceiling_animated.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 3.0
},
},
{
name="default_torch_animated.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 3.0
},
},
},
inventory_image = "default_torch_on_floor.png",
wield_image = "default_torch_on_floor.png",
paramtype = "light",
paramtype2 = "wallmounted",
sunlight_propagates = true,
is_ground_content = false,
walkable = false,
light_source = 13,
selection_box = {
type = "wallmounted",
wall_top = {-0.1, 0.5-0.6, -0.1, 0.1, 0.5, 0.1},
wall_bottom = {-0.1, -0.5, -0.1, 0.1, -0.5+0.6, 0.1},
wall_side = {-0.5, -0.3, -0.1, -0.5+0.3, 0.3, 0.1},
},
groups = {choppy=2,dig_immediate=3,flammable=1,attached_node=1},
legacy_wallmounted = true,
--sounds = default.node_sound_defaults(),
})
minetest.register_craft({
output = 'walking_light:helmet_diamond',
recipe = {
{'default:torch'},
{'3d_armor:helmet_diamond'},
}
})
minetest.register_craft({
output = 'walking_light:megatorch',
recipe = {
{'default:torch', 'default:torch', 'default:torch'},
{'default:torch', 'default:torch', 'default:torch'},
{'default:torch', 'default:torch', 'default:torch'},
}
})
minetest.register_chatcommand("walking_light_clear_light", {
params = "<size>",
description = "Remove light nodes from the area",
func = function(name, param)
if not minetest.check_player_privs(name, {server=true}) then
return false, "You need the server privilege to use mapclearlight"
end
local pos = vector.round(minetest.get_player_by_name(name):get_pos())
local size = tonumber(param) or 40
for i,v in ipairs({"walking_light:light", "walking_light:light_debug"}) do
point = minetest.find_node_near(pos, size/2, v)
while point do
remove_light(nil, point)
oldpoint = point
point = minetest.find_node_near(pos, size/2, v)
if poseq(oldpoint, point) then
return false, "Failed... infinite loop detected"
end
end
end
return true, "Done."
end,
})
minetest.register_chatcommand("walking_light_add_light", {
params = "<size>",
description = "Add walking_light:light to a position, without a player owning it",
func = function(name, param)
if not minetest.check_player_privs(name, {server=true}) then
return false, "You need the server privilege to use mapaddlight"
end
local pos = vector.round(minetest.get_player_by_name(name):get_pos())
pos = vector.new(pos.x, pos.y + 1, pos.z)
if pos then
mt_add_node(pos,{type="node",name=walking_light_node})
end
return true, "Done."
end,
})
minetest.register_chatcommand("walking_light_debug", {
description = "Change to debug mode, so light blocks are visible.",
func = function(name, param)
if not minetest.check_player_privs(name, {server=true}) then
return false, "You need the server privilege to use walking_light_debug"
end
walking_light_debug = not walking_light_debug
update_walking_light_node()
return true, "Done."
end,
})
-- vim: ts=4 sw=4 softtabstop=4 smarttab noexpandtab

View File

@ -0,0 +1,2 @@
name = walking_light
depends = default

View File

@ -0,0 +1,89 @@
core.register_node("walking_light:light_debug", {
drawtype = "glasslike",
tiles = {"walking_light_debug.png"},
inventory_image = core.inventorycube("walking_light.png"),
paramtype = "light",
walkable = false,
is_ground_content = true,
sunlight_propagates = true,
light_source = 13,
selection_box = {
type = "fixed",
fixed = {0, 0, 0, 0, 0, 0},
},
})
core.register_node("walking_light:light", {
drawtype = "glasslike",
tiles = {"walking_light.png"},
inventory_image = core.inventorycube("walking_light.png"),
paramtype = "light",
walkable = false,
is_ground_content = true,
sunlight_propagates = true,
light_source = 13,
selection_box = {
type = "fixed",
fixed = {0, 0, 0, 0, 0, 0},
},
})
core.register_node("walking_light:megatorch", {
description = "Megatorch",
drawtype = "torchlike",
tiles = {
{
name = "default_torch_on_floor_animated.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 3.0,
},
},
{
name = "default_torch_on_ceiling_animated.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 3.0,
},
},
{
name = "default_torch_animated.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 3.0,
},
},
},
inventory_image = "default_torch_on_floor.png",
wield_image = "default_torch_on_floor.png",
paramtype = "light",
paramtype2 = "wallmounted",
sunlight_propagates = true,
is_ground_content = false,
walkable = false,
light_source = 13,
selection_box = {
type = "wallmounted",
wall_top = {-0.1, 0.5-0.6, -0.1, 0.1, 0.5, 0.1},
wall_bottom = {-0.1, -0.5, -0.1, 0.1, -0.5+0.6, 0.1},
wall_side = {-0.5, -0.3, -0.1, -0.5+0.3, 0.3, 0.1},
},
groups = {choppy=2, dig_immediate=3, flammable=1, attached_node=1},
legacy_wallmounted = true,
})
core.register_craft({
output = "walking_light:megatorch",
recipe = {
{"default:torch", "default:torch", "default:torch"},
{"default:torch", "default:torch", "default:torch"},
{"default:torch", "default:torch", "default:torch"},
}
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 902 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 B