123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- 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:get_pos())),
- vector.round(vector.multiply(player:get_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)
- ---TEST
- --wielded_light.register_item_light('default:dirt', 14)
|