local update_interval = 0.2 local level_delta = 2 local shiny_items = {} --- Shining API --- wielded_light = {} function wielded_light.update_light(pos, light_level) local around_vector = { {x=0, y=0, z=0}, {x=0, y=1, z=0}, {x=0, y=-1, z=0}, {x=1, y=0, z=0}, {x=-1, y=0, z=0}, {x=0, y=0, z=1}, {x=0, y=0, z=1}, } local do_update = false local old_value = 0 local timer local light_pos for _, around in ipairs(around_vector) do light_pos = vector.add(pos, around) local name = minetest.get_node(light_pos).name if name == "air" and (minetest.get_node_light(light_pos) or 0) < light_level then do_update = true break elseif name:sub(1,13) == "wielded_light" then -- Update existing light node and timer old_value = tonumber(name:sub(15)) if light_level > old_value then do_update = true else timer = minetest.get_node_timer(light_pos) local elapsed = timer:get_elapsed() if elapsed > (update_interval * 1.5) then -- The timer is set to 3x update_interval -- This node was not updated the last interval and may -- is disabled before the next step -- Therefore the light should be re-set to avoid flicker do_update = true end end break end end if do_update then timer = timer or minetest.get_node_timer(light_pos) if light_level ~= old_value then minetest.swap_node(light_pos, {name = "wielded_light:"..light_level}) end timer:start(update_interval*3) end end function wielded_light.update_light_by_item(item, pos) local stack = ItemStack(item) local light_level = shiny_items[stack:get_name()] local itemdef = stack:get_definition() if not light_level and not itemdef then return end light_level = light_level or ((itemdef.light_source or 0) - level_delta) if light_level > 0 then wielded_light.update_light(pos, light_level) end end function wielded_light.register_item_light(itemname, light_level) shiny_items[itemname] = light_level end -- Register helper nodes for i=1, 14 do minetest.register_node("wielded_light:"..i, { drawtype = "airlike", groups = {not_in_creative_inventory = 1}, walkable = false, paramtype = "light", sunlight_propagates = true, light_source = i, pointable = false, buildable_to = true, drop = {}, on_timer = function(pos, elapsed) minetest.swap_node(pos, {name = "air"}) end, }) end -- Wielded item shining globalstep local timer = 0 minetest.register_globalstep(function(dtime) timer = timer + dtime; if timer < update_interval then return end timer = 0 for _, player in pairs(minetest.get_connected_players()) do -- predict where the player will be the next time we place the light -- assume that on average we're slightly past 1/2 of the next interval, hence 1.5 -- (since the scheduling is a bit behind) -- experimentally this also works nicely local pos = vector.add ( vector.add({x = 0, y = 1, z = 0}, vector.round(player:getpos())), vector.round(vector.multiply(player:get_player_velocity(), update_interval * 1.5)) ) wielded_light.update_light_by_item(player:get_wielded_item(), pos) end end) -- Dropped item on_step override -- https://github.com/minetest/minetest/issues/6909 local builtin_item = minetest.registered_entities["__builtin:item"] local item = { on_step = function(self, dtime, moveresult) builtin_item.on_step(self, dtime, moveresult) self.shining_timer = (self.shining_timer or 0) + dtime if self.shining_timer >= update_interval then self.shining_timer = 0 local pos = self.object:get_pos() if pos then wielded_light.update_light_by_item(self.itemstring, pos) end end end } setmetatable(item, {__index = builtin_item}) minetest.register_entity(":__builtin:item", item) --lightsabers wielded_light.register_item_light('adv_lightsabers:lightsaber_single_green_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_single_blue_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_single_red_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_single_yellow_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_single_purple_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_single_white_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_single_black_on', 5) wielded_light.register_item_light('adv_lightsabers:lightsaber_double_green_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_double_blue_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_double_red_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_double_yellow_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_double_purple_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_double_white_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_cross_green_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_cross_blue_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_cross_red_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_cross_yellow_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_cross_purple_on', 14) wielded_light.register_item_light('adv_lightsabers:lightsaber_cross_white_on', 14) --kyber crystals wielded_light.register_item_light('adv_lightsabers:kyber_crystal', 4) wielded_light.register_item_light('adv_lightsabers:kyber_crystal_green', 7) wielded_light.register_item_light('adv_lightsabers:kyber_crystal_blue', 7) wielded_light.register_item_light('adv_lightsabers:kyber_crystal_red', 7) wielded_light.register_item_light('adv_lightsabers:kyber_crystal_yellow', 7) wielded_light.register_item_light('adv_lightsabers:kyber_crystal_purple', 7) wielded_light.register_item_light('adv_lightsabers:kyber_crystal_white', 7) wielded_light.register_item_light('adv_lightsabers:kyber_crystal_black', 2) --torch wielded_light.register_item_light('default:torch', 12) --candle wielded_light.register_item_light('ethereal:candle', 11)