Replace wlight mod with wielded_light v2021-07-15...
https://content.minetest.net/packages/bell07/wielded_light/
This commit is contained in:
parent
2f773cfaa7
commit
bfa6bbb612
@ -63,7 +63,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])
|
||||
* [wlight][] ([MIT][lic.wlight]) -- version: [1.0][ver.wlight] *2021-06-26*
|
||||
* [wielded_light][] ([GPL][lic.gpl3.0]) -- version: 2021-07-15
|
||||
* 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]
|
||||
@ -245,7 +245,6 @@ The game includes the mods from the default [minetest_game](https://github.com/m
|
||||
* [vehicles](https://forum.minetest.net/viewtopic.php?t=15610)
|
||||
* [villagers](https://forum.minetest.net/viewtopic.php?t=17915)
|
||||
* [weather](https://content.minetest.net/packages/theFox/weather/)
|
||||
* [wielded_light](https://content.minetest.net/packages/bell07/wielded_light/)
|
||||
* [wildcow](https://forum.minetest.net/viewtopic.php?t=25739)
|
||||
* [witches](https://content.minetest.net/packages/FreeLikeGNU/witches/)
|
||||
* [xpro](https://forum.minetest.net/viewtopic.php?t=20499) (XP and Levels)
|
||||
@ -424,8 +423,8 @@ The game includes the mods from the default [minetest_game](https://github.com/m
|
||||
[weather]: https://forum.minetest.net/viewtopic.php?t=5245
|
||||
[whinny]: https://github.com/AntumMT/mod-whinny
|
||||
[whitelist]: https://forum.minetest.net/viewtopic.php?t=8434
|
||||
[wielded_light]: https://content.minetest.net/packages/bell07/wielded_light/
|
||||
[windmill]: https://forum.minetest.net/viewtopic.php?id=7440
|
||||
[wlight]: https://content.minetest.net/packages/AntumDeluge/wlight/
|
||||
[workbench]: https://forum.minetest.net/viewtopic.php?t=14085
|
||||
[xtraarmor]: https://forum.minetest.net/viewtopic.php?t=16645
|
||||
|
||||
@ -512,7 +511,6 @@ The game includes the mods from the default [minetest_game](https://github.com/m
|
||||
[lic.whinny]: mods/mobiles/whinny/LICENSE.txt
|
||||
[lic.whitelist]: mods/admin/whitelist/LICENSE.txt
|
||||
[lic.windmill]: mods/buildings/windmill/README.md
|
||||
[lic.wlight]: mods/lighting/wlight/LICENSE.txt
|
||||
[lic.workbench]: mods/tools/workbench/LICENSE.txt
|
||||
|
||||
[lic.cc0]: doc/licenses/CC0.txt
|
||||
@ -681,7 +679,6 @@ The game includes the mods from the default [minetest_game](https://github.com/m
|
||||
[ver.whinny]: https://github.com/AntumMT/mod-whinny/tree/32f2d9f
|
||||
[ver.whitelist]: https://github.com/AntumMT/mod-whitelist/releases/tag/v1.1
|
||||
[ver.windmill]: https://github.com/Sokomine/windmill/tree/47b029d
|
||||
[ver.wlight]: https://github.com/AntumMT/mod-wlight/releases/tag/v1.0
|
||||
[ver.workbench]: https://github.com/AntumMT/mod-workbench/releases/tag/v1.0
|
||||
|
||||
[patch.3d_armor]: https://github.com/AntumMT/mp-3d_armor/tree/e3e9877
|
||||
|
@ -1709,14 +1709,6 @@ coloredwood_enable_stairsplus = true
|
||||
####################
|
||||
|
||||
|
||||
# *** wlight ***
|
||||
|
||||
## Enables wlight:megatorch item.
|
||||
# type: bool
|
||||
# default: true
|
||||
#wlight.enable_megatorch = true
|
||||
|
||||
|
||||
# *** wardrobe ***
|
||||
|
||||
## Number of skins shown per page.
|
||||
|
24
mods/lighting/wielded_light/README.md
Normal file
24
mods/lighting/wielded_light/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# wielded_light mod for Minetest
|
||||
|
||||
Idea taken from torches_wieldlight in https://github.com/minetest-mods/torches, but written from scratch and usable for all shining items.
|
||||
|
||||

|
||||
|
||||
All bright nodes with light value > 2 lighten the player environment if wielded, with value fewer by 2. (Torch 13->11 for example)
|
||||
|
||||
Dependencies: none
|
||||
|
||||
License: [GPL-3](https://github.com/bell07/minetest-wielded_light/blob/master/LICENSE)
|
||||
|
||||
|
||||
Shining API:
|
||||
|
||||
`function wielded_light.update_light(pos, light_level)`
|
||||
Enable or update the shining at pos with light_level for 0.6 seconds. Can be used in any on_step call to get other entitys shining for example
|
||||
|
||||
|
||||
`wielded_light.register_item_light(itemname, light_level)`
|
||||
Override or set custom light level to an item. This does not change the item/node definition, just the lighting in this mod.
|
||||
|
||||
`function wielded_light.update_light_by_item(stack, pos)`
|
||||
Update light at pos using item shining settings -from registered item_light or from item definition
|
1
mods/lighting/wielded_light/depends.txt
Normal file
1
mods/lighting/wielded_light/depends.txt
Normal file
@ -0,0 +1 @@
|
||||
default?
|
581
mods/lighting/wielded_light/init.lua
Normal file
581
mods/lighting/wielded_light/init.lua
Normal file
@ -0,0 +1,581 @@
|
||||
local mod_name = minetest.get_current_modname()
|
||||
|
||||
-- Node replacements that emit light
|
||||
-- Sets of lighting_node={ node=original_node, level=light_level }
|
||||
local lighting_nodes = {}
|
||||
|
||||
-- The nodes that can be replaced with lighting nodes
|
||||
-- Sets of original_node={ [1]=lighting_node_1, [2]=lighting_node_2, ... }
|
||||
local lightable_nodes = {}
|
||||
|
||||
-- Prefixes used for each node so we can avoid overlap
|
||||
-- Pairs of prefix=original_node
|
||||
local lighting_prefixes = {}
|
||||
|
||||
-- node_name=true pairs of lightable nodes that are liquids and can flood some light sources
|
||||
local lightable_liquids = {}
|
||||
|
||||
-- How often will the positions of lights be recalculated
|
||||
local update_interval = 0.2
|
||||
|
||||
-- How long until a previously lit node should be updated - reduces flicker
|
||||
local removal_delay = update_interval * 0.5
|
||||
|
||||
-- How often will a node attempt to check itself for deletion
|
||||
local cleanup_interval = update_interval * 3
|
||||
|
||||
-- How far in the future will the position be projected based on the velocity
|
||||
local velocity_projection = update_interval * 1
|
||||
|
||||
-- How many light levels should an item held in the hand be reduced by, compared to the placed node
|
||||
-- does not apply to manually registered light levels
|
||||
local level_delta = 2
|
||||
|
||||
-- item=light_level pairs of registered wielded lights
|
||||
local shiny_items = {}
|
||||
|
||||
-- List of custom callbacks for each update step
|
||||
local update_callbacks = {}
|
||||
local update_player_callbacks = {}
|
||||
|
||||
-- position={id=light_level} sets of known about light sources and their levels by position
|
||||
local active_lights = {}
|
||||
|
||||
--[[ Sets of entities being tracked, in the form:
|
||||
entity_id = {
|
||||
obj = entity,
|
||||
items = {
|
||||
category_id..entity_id = {
|
||||
level = light_level,
|
||||
item? = item_name
|
||||
}
|
||||
},
|
||||
update = true | false,
|
||||
pos? = position_vector,
|
||||
offset? = offset_vector,
|
||||
}
|
||||
]]
|
||||
local tracked_entities = {}
|
||||
|
||||
-- position=true pairs of positions that need to be recaculated this update step
|
||||
local light_recalcs = {}
|
||||
|
||||
--[[
|
||||
Using 2-digit hex codes for categories
|
||||
Starts at 00, ends at FF
|
||||
This makes it easier extract `uid` from `cat_id..uid` by slicing off 2 characters
|
||||
The category ID must be of a fixed length (2 characters)
|
||||
]]
|
||||
local cat_id = 0
|
||||
local cat_codes = {}
|
||||
local function get_light_category_id(cat)
|
||||
-- If the category id does not already exist generate a new one
|
||||
if not cat_codes[cat] then
|
||||
if cat_id >= 256 then
|
||||
error("Wielded item category limit exceeded, maximum 256 wield categories")
|
||||
end
|
||||
local code = string.format("%02x", cat_id)
|
||||
cat_id = cat_id+1
|
||||
cat_codes[cat] = code
|
||||
end
|
||||
-- If the category id does exist, return it
|
||||
return cat_codes[cat]
|
||||
end
|
||||
|
||||
-- Log an error coming from this mod
|
||||
local function error_log(message, ...)
|
||||
minetest.log("error", "[Wielded Light] " .. (message:format(...)))
|
||||
end
|
||||
|
||||
-- Is a node lightable and a liquid capable of flooding some light sources
|
||||
local function is_lightable_liquid(pos)
|
||||
local node = minetest.get_node_or_nil(pos)
|
||||
if not node then return end
|
||||
return lightable_liquids[node.name]
|
||||
end
|
||||
|
||||
-- Check if an entity instance still exists in the world
|
||||
local function is_entity_valid(entity)
|
||||
return entity and (entity.obj:is_player() or entity.obj:get_entity_name() or false)
|
||||
end
|
||||
|
||||
-- Get the projected position of an entity based on its velocity, rounded to the nearest block
|
||||
local function entity_pos(obj, offset)
|
||||
if not offset then offset = { x=0, y=0, z=0 } end
|
||||
return wielded_light.get_light_position(
|
||||
vector.round(
|
||||
vector.add(
|
||||
vector.add(
|
||||
offset,
|
||||
obj:get_pos()
|
||||
),
|
||||
vector.multiply(
|
||||
obj:get_player_velocity(),
|
||||
velocity_projection
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
-- Add light to active light list and mark position for update
|
||||
local function add_light(pos, id, light_level)
|
||||
if not active_lights[pos] then
|
||||
active_lights[pos] = {}
|
||||
end
|
||||
if active_lights[pos][id] ~= light_level then
|
||||
-- minetest.log("error", "add "..id.." "..pos.." "..tostring(light_level))
|
||||
active_lights[pos][id] = light_level
|
||||
light_recalcs[pos] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- Remove light from active light list and mark position for update
|
||||
local function remove_light(pos, id)
|
||||
if not active_lights[pos] then return end
|
||||
-- minetest.log("error", "rem "..id.." "..pos)
|
||||
active_lights[pos][id] = nil
|
||||
minetest.after(removal_delay, function ()
|
||||
light_recalcs[pos] = true
|
||||
end)
|
||||
end
|
||||
|
||||
-- Track an entity's position and update its light, will be called on every update step
|
||||
local function update_entity(entity)
|
||||
local pos = entity_pos(entity.obj, entity.offset)
|
||||
local pos_str = pos and minetest.pos_to_string(pos)
|
||||
|
||||
-- If the position has changed, remove the old light and mark the entity for update
|
||||
if entity.pos and pos_str ~= entity.pos then
|
||||
entity.update = true
|
||||
for id,_ in pairs(entity.items) do
|
||||
remove_light(entity.pos, id)
|
||||
end
|
||||
end
|
||||
|
||||
-- Update the recorded position
|
||||
entity.pos = pos_str
|
||||
|
||||
-- If the position is still loaded, pump the timer up so it doesn't get removed
|
||||
if pos then
|
||||
-- If the entity is marked for an update, add the light in the position if it emits light
|
||||
if entity.update then
|
||||
for id, item in pairs(entity.items) do
|
||||
if item.level > 0 and not (item.floodable and is_lightable_liquid(pos)) then
|
||||
add_light(pos_str, id, item.level)
|
||||
else
|
||||
remove_light(pos_str, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
minetest.get_node_timer(pos):start(cleanup_interval)
|
||||
end
|
||||
entity.update = false
|
||||
end
|
||||
|
||||
-- Replace a lighting node with its original counterpart
|
||||
local function reset_lighting_node(pos)
|
||||
local existing_node = minetest.get_node(pos)
|
||||
local lighting_node = wielded_light.get_lighting_node(existing_node.name)
|
||||
if not lighting_node then
|
||||
return
|
||||
end
|
||||
minetest.swap_node(pos, { name = lighting_node.node })
|
||||
end
|
||||
|
||||
-- Will be run once the node timer expires
|
||||
local function cleanup_timer_callback(pos, elapsed)
|
||||
local pos_str = minetest.pos_to_string(pos)
|
||||
local lights = active_lights[pos_str]
|
||||
-- If no active lights for this position, remove itself
|
||||
if not lights then
|
||||
reset_lighting_node(pos)
|
||||
else
|
||||
-- Clean up any tracked entities for this position that no longer exist
|
||||
for id,_ in pairs(lights) do
|
||||
local uid = string.sub(id,3)
|
||||
local entity = tracked_entities[uid]
|
||||
if not is_entity_valid(entity) then
|
||||
remove_light(pos_str, id)
|
||||
end
|
||||
end
|
||||
minetest.get_node_timer(pos):start(cleanup_interval)
|
||||
end
|
||||
end
|
||||
|
||||
-- Recalculate the total light level for a given position and update the light level there
|
||||
local function recalc_light(pos)
|
||||
-- If not in active lights list we can't do anything
|
||||
if not active_lights[pos] then return end
|
||||
|
||||
-- Calculate the light level of the node
|
||||
local any_light = false
|
||||
local max_light = 0
|
||||
for id, light_level in pairs(active_lights[pos]) do
|
||||
any_light = true
|
||||
if light_level > max_light then
|
||||
max_light = light_level
|
||||
end
|
||||
end
|
||||
|
||||
-- Convert the position back to a vector
|
||||
local pos_vec = minetest.string_to_pos(pos)
|
||||
|
||||
-- If no items in this position, delete it from the list and remove any light node
|
||||
if not any_light then
|
||||
active_lights[pos] = nil
|
||||
reset_lighting_node(pos_vec)
|
||||
return
|
||||
end
|
||||
|
||||
-- If no light in this position remove any light node
|
||||
if max_light == 0 then
|
||||
reset_lighting_node(pos_vec)
|
||||
return
|
||||
end
|
||||
|
||||
-- Limit the light level
|
||||
max_light = math.min(max_light, minetest.LIGHT_MAX)
|
||||
|
||||
-- Get the current light level in this position
|
||||
local name = minetest.get_node(pos_vec).name
|
||||
local old_value = wielded_light.level_of_lighting_node(name) or 0
|
||||
|
||||
-- If the light level has changed, set the coresponding light node and initiate the cleanup timer
|
||||
if old_value ~= max_light then
|
||||
local node_name = lightable_nodes[name] and name or lighting_nodes[name].node
|
||||
minetest.swap_node(pos_vec, {
|
||||
name = lightable_nodes[node_name][max_light]
|
||||
})
|
||||
minetest.get_node_timer(pos_vec):start(cleanup_interval)
|
||||
end
|
||||
end
|
||||
|
||||
local timer = 0
|
||||
-- Will be run on every global step
|
||||
local function global_timer_callback(dtime)
|
||||
-- Only run once per update interval, global step will be called much more often than that
|
||||
timer = timer + dtime;
|
||||
if timer < update_interval then
|
||||
return
|
||||
end
|
||||
timer = 0
|
||||
|
||||
-- Run all custom player callbacks for each player
|
||||
local connected_players = minetest.get_connected_players()
|
||||
for _,callback in pairs(update_player_callbacks) do
|
||||
for _, player in pairs(connected_players) do
|
||||
callback(player)
|
||||
end
|
||||
end
|
||||
|
||||
-- Run all custom callbacks
|
||||
for _,callback in pairs(update_callbacks) do
|
||||
callback()
|
||||
end
|
||||
|
||||
-- Look at each tracked entity and update its position
|
||||
for uid, entity in pairs(tracked_entities) do
|
||||
if is_entity_valid(entity) then
|
||||
update_entity(entity)
|
||||
else
|
||||
-- If the entity no longer exists, stop tracking it
|
||||
tracked_entities[uid] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Recalculate light levels
|
||||
for pos,_ in pairs(light_recalcs) do
|
||||
recalc_light(pos)
|
||||
end
|
||||
light_recalcs = {}
|
||||
end
|
||||
|
||||
--- Shining API ---
|
||||
wielded_light = {}
|
||||
|
||||
-- Registers a callback to be called every time the update interval is passed
|
||||
function wielded_light.register_lightstep(callback)
|
||||
table.insert(update_callbacks, callback)
|
||||
end
|
||||
|
||||
-- Registers a callback to be called for each player every time the update interval is passed
|
||||
function wielded_light.register_player_lightstep(callback)
|
||||
table.insert(update_player_callbacks, callback)
|
||||
end
|
||||
|
||||
-- Returns the node name for a given light level
|
||||
function wielded_light.lighting_node_of_level(light_level, prefix)
|
||||
return mod_name..":"..(prefix or "")..light_level
|
||||
end
|
||||
|
||||
-- Gets the light level for a given node name, inverse of lighting_node_of_level
|
||||
function wielded_light.level_of_lighting_node(node_name)
|
||||
local lighting_node = wielded_light.get_lighting_node(node_name)
|
||||
if lighting_node then
|
||||
return lighting_node.level
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if a node name is one of the wielded light nodes
|
||||
function wielded_light.get_lighting_node(node_name)
|
||||
return lighting_nodes[node_name]
|
||||
end
|
||||
|
||||
-- Register any node as lightable, register all light level variations for it
|
||||
function wielded_light.register_lightable_node(node_name, property_overrides, custom_prefix)
|
||||
-- Node name must be string
|
||||
if type(node_name) ~= "string" then
|
||||
error_log("You must provide a node name to be registered as lightable, '%s' given.", type(node_name))
|
||||
return
|
||||
end
|
||||
|
||||
-- Node must already be registered
|
||||
local original_definition = minetest.registered_nodes[node_name]
|
||||
if not original_definition then
|
||||
error_log("The node '%s' cannot be registered as lightable because it does not exist.", node_name)
|
||||
return
|
||||
end
|
||||
|
||||
-- Decide the prefix for the lighting node
|
||||
local prefix = custom_prefix or node_name:gsub(":", "_", 1, true) .. "_"
|
||||
if lighting_prefixes[prefix] then
|
||||
error_log("The lighting prefix '%s' cannot be used for '%s' as it is already used for '%s'.", prefix, node_name, lighting_prefixes[prefix])
|
||||
return
|
||||
end
|
||||
lighting_prefixes[prefix] = node_name
|
||||
|
||||
-- Default for property overrides
|
||||
if not property_overrides then property_overrides = {} end
|
||||
|
||||
-- Copy the node definition and provide required settings for a lighting node
|
||||
local new_definition = table.copy(original_definition)
|
||||
new_definition.on_timer = cleanup_timer_callback
|
||||
new_definition.paramtype = "light"
|
||||
new_definition.mod_origin = mod_name
|
||||
new_definition.groups = new_definition.groups or {}
|
||||
new_definition.groups.not_in_creative_inventory = 1
|
||||
|
||||
-- Allow any properties to be overridden on registration
|
||||
for prop, val in pairs(property_overrides) do
|
||||
new_definition[prop] = val
|
||||
end
|
||||
|
||||
-- If it's a liquid, we need to stop it flowing
|
||||
if new_definition.groups.liquid then
|
||||
new_definition.liquid_range = 0
|
||||
lightable_liquids[node_name] = true
|
||||
end
|
||||
|
||||
-- Register the lighting nodes
|
||||
lightable_nodes[node_name] = {}
|
||||
for i=1, minetest.LIGHT_MAX do
|
||||
local lighting_node_name = wielded_light.lighting_node_of_level(i, prefix)
|
||||
|
||||
-- Index for quick finding later
|
||||
lightable_nodes[node_name][i] = lighting_node_name
|
||||
lighting_nodes[lighting_node_name] = {
|
||||
node = node_name,
|
||||
level = i
|
||||
}
|
||||
|
||||
-- Copy the base definition and apply the light level
|
||||
local level_definition = table.copy(new_definition)
|
||||
level_definition.light_source = i
|
||||
|
||||
-- If it's a liquid, we need to stop it replacing itself with the original
|
||||
if level_definition.groups.liquid then
|
||||
level_definition.liquid_alternative_source = lighting_node_name
|
||||
level_definition.liquid_alternative_flowing = lighting_node_name
|
||||
end
|
||||
|
||||
minetest.register_node(lighting_node_name, level_definition)
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if node can have a wielded light node placed in it
|
||||
function wielded_light.is_lightable_node(node_pos)
|
||||
local name = minetest.get_node(node_pos).name
|
||||
if lightable_nodes[name] then
|
||||
return true
|
||||
elseif wielded_light.get_lighting_node(name) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Gets the closest position to pos that's a lightable node
|
||||
function wielded_light.get_light_position(pos)
|
||||
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},
|
||||
}
|
||||
for _, around in ipairs(around_vector) do
|
||||
local light_pos = vector.add(pos, around)
|
||||
if wielded_light.is_lightable_node(light_pos) then
|
||||
return light_pos
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Gets the emitted light level of a given item name
|
||||
function wielded_light.get_light_def(item_name)
|
||||
-- Invalid item? No light
|
||||
if not item_name or item_name == "" then
|
||||
return 0, false
|
||||
end
|
||||
|
||||
-- If the item is cached return the cached level
|
||||
local cached_definition = shiny_items[item_name]
|
||||
if cached_definition then
|
||||
return cached_definition.level, cached_definition.floodable
|
||||
end
|
||||
|
||||
-- Get the item definition
|
||||
local stack = ItemStack(item_name)
|
||||
local itemdef = stack:get_definition()
|
||||
|
||||
-- If invalid, no light
|
||||
if not itemdef then
|
||||
return 0, false
|
||||
end
|
||||
|
||||
-- Get the light level of an item from its definition
|
||||
-- Reduce the light level by level_delta - original functionality
|
||||
-- Limit between 0 and the max light level
|
||||
return math.min(math.max((itemdef.light_source or 0) - level_delta, 0), minetest.LIGHT_MAX), itemdef.floodable
|
||||
end
|
||||
|
||||
-- Register an item as shining
|
||||
function wielded_light.register_item_light(item_name, light_level, floodable)
|
||||
if shiny_items[item_name] then
|
||||
if light_level then
|
||||
shiny_items[item_name].level = light_level
|
||||
end
|
||||
if floodable ~= nil then
|
||||
shiny_items[item_name].floodable = floodable
|
||||
end
|
||||
else
|
||||
if floodable == nil then
|
||||
local stack = ItemStack(item_name)
|
||||
local itemdef = stack:get_definition()
|
||||
floodable = itemdef.floodable
|
||||
end
|
||||
shiny_items[item_name] = {
|
||||
level = light_level,
|
||||
floodable = floodable or false
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- Mark an item as floodable or not
|
||||
function wielded_light.register_item_floodable(item_name, floodable)
|
||||
if floodable == nil then floodable = true end
|
||||
if shiny_items[item_name] then
|
||||
shiny_items[item_name].floodable = floodable
|
||||
else
|
||||
local calced_level = wielded_light.get_light_def(item_name)
|
||||
shiny_items[item_name] = {
|
||||
level = calced_level,
|
||||
floodable = floodable
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- Keep track of an item entity. Should be called once for an item
|
||||
function wielded_light.track_item_entity(obj, cat, item)
|
||||
local light_level, light_is_floodable = wielded_light.get_light_def(item)
|
||||
-- If the item does not emit light do not track it
|
||||
if light_level <= 0 then return end
|
||||
|
||||
-- Generate the uid for the item and the id for the light category
|
||||
local uid = tostring(obj)
|
||||
local id = get_light_category_id(cat)..uid
|
||||
|
||||
-- Create the main tracking object for this item instance if it does not already exist
|
||||
if not tracked_entities[uid] then
|
||||
tracked_entities[uid] = { obj=obj, items={}, update = true }
|
||||
end
|
||||
|
||||
-- Create the item tracking object for this item + category
|
||||
tracked_entities[uid].items[id] = { level=light_level, floodable=light_is_floodable }
|
||||
|
||||
-- Add the light in on creation so it's immediate
|
||||
local pos = entity_pos(obj)
|
||||
local pos_str = pos and minetest.pos_to_string(pos)
|
||||
if pos_str then
|
||||
if not (light_is_floodable and is_lightable_liquid(pos)) then
|
||||
add_light(pos_str, id, light_level)
|
||||
end
|
||||
end
|
||||
tracked_entities[uid].pos = pos_str
|
||||
end
|
||||
|
||||
-- A player's light should appear near their head not their feet
|
||||
local player_height_offset = { x=0, y=1, z=0 }
|
||||
|
||||
-- Keep track of a user / player entity. Should be called as often as the user updates
|
||||
function wielded_light.track_user_entity(obj, cat, item)
|
||||
-- Generate the uid for the player and the id for the light category
|
||||
local uid = tostring(obj)
|
||||
local id = get_light_category_id(cat)..uid
|
||||
|
||||
-- Create the main tracking object for this player instance if it does not already exist
|
||||
if not tracked_entities[uid] then
|
||||
tracked_entities[uid] = { obj=obj, items={}, offset = player_height_offset, update = true }
|
||||
end
|
||||
|
||||
local tracked_entity = tracked_entities[uid]
|
||||
local tracked_item = tracked_entity.items[id]
|
||||
|
||||
-- If the item being tracked for the player changes, update the item tracking object for this item + category
|
||||
if not tracked_item or tracked_item.item ~= item then
|
||||
local light_level, light_is_floodable = wielded_light.get_light_def(item)
|
||||
tracked_entity.items[id] = { level=light_level, item=item, floodable=light_is_floodable }
|
||||
tracked_entity.update = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Setup --
|
||||
|
||||
-- Wielded item shining globalstep
|
||||
minetest.register_globalstep(global_timer_callback)
|
||||
|
||||
-- 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, ...)
|
||||
builtin_item.on_step(self, dtime, ...)
|
||||
-- Register an item once for tracking
|
||||
-- If it's already being tracked, exit
|
||||
if self.wielded_light then return end
|
||||
self.wielded_light = true
|
||||
local stack = ItemStack(self.itemstring)
|
||||
local item_name = stack:get_name()
|
||||
wielded_light.track_item_entity(self.object, "item", item_name)
|
||||
end
|
||||
}
|
||||
setmetatable(item, {__index = builtin_item})
|
||||
minetest.register_entity(":__builtin:item", item)
|
||||
|
||||
-- Track a player's wielded item
|
||||
wielded_light.register_player_lightstep(function (player)
|
||||
wielded_light.track_user_entity(player, "wield", player:get_wielded_item():get_name())
|
||||
end)
|
||||
|
||||
-- Register helper nodes
|
||||
local water_name = "default:water_source"
|
||||
if minetest.get_modpath("hades_core") then
|
||||
water_name = "hades_core:water_source"
|
||||
end
|
||||
|
||||
wielded_light.register_lightable_node("air", nil, "")
|
||||
wielded_light.register_lightable_node(water_name, nil, "water_")
|
||||
wielded_light.register_lightable_node("default:river_water_source", nil, "river_water_")
|
||||
|
||||
---TEST
|
||||
--wielded_light.register_item_light('default:dirt', 14)
|
2
mods/lighting/wielded_light/mod.conf
Normal file
2
mods/lighting/wielded_light/mod.conf
Normal file
@ -0,0 +1,2 @@
|
||||
name = wielded_light
|
||||
optional_depends = default, hades_core
|
BIN
mods/lighting/wielded_light/screenshot.png
Normal file
BIN
mods/lighting/wielded_light/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 329 KiB |
@ -1,24 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2021 Jordan Irwin (AntumDeluge)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
Code by Echo & petermaloney originally licensed under CC0
|
@ -1,72 +0,0 @@
|
||||
## Walking Light
|
||||
|
||||
### Description:
|
||||
|
||||
A mod for [Minetest](http://minetest.net/) that illuminates the area around a player when wielding a light-emitting item. Also supports equipped armor with [3d_armor](https://content.minetest.net/packages/stu/3d_armor/).
|
||||
|
||||

|
||||
|
||||
#### History:
|
||||
|
||||
- forked from [v0.6][forum.echo] of Echo's *walking_light*
|
||||
- forked from [Git commit 766ef0f](https://github.com/petermaloney/walking_light/tree/766ef0f) of petermaloney's *walking_light*
|
||||
|
||||
### Licensing:
|
||||
|
||||
- Code: [MIT](LICENSE.txt)
|
||||
- Textures: [CC0](https://creativecommons.org/publicdomain/zero/1.0/legalcode)
|
||||
|
||||
### Requirements:
|
||||
|
||||
```
|
||||
- Minetest minimum version: 5.0.0
|
||||
- Depends: none
|
||||
- Optional depends: default (for torch & megatorch)
|
||||
- Privileges: server (for using chat commands)
|
||||
```
|
||||
|
||||
### Usage:
|
||||
|
||||
Main methods:
|
||||
|
||||
```
|
||||
wlight.register_item(iname, radius)
|
||||
- Registers an item to emit light when wielded.
|
||||
- `iname`: Item technical name.
|
||||
- `radius`: Distance light will reach (max: 10).
|
||||
|
||||
wlight.register_armor(iname, radius, litem)
|
||||
- Registers an item to emit light when equipped in armor inventory.
|
||||
- `iname`: Item technical name.
|
||||
- `radius`: Distance light will reach (max: 10).
|
||||
- `litem`: Whether or not this item should also be registered with `wlight.register_item` (default: true).
|
||||
```
|
||||
|
||||
Settings:
|
||||
|
||||
```
|
||||
wlight.enable_megatorch
|
||||
- Enables wlight:megatorch item.
|
||||
- default: true
|
||||
```
|
||||
|
||||
### Links:
|
||||
|
||||
- [](https://content.minetest.net/packages/AntumDeluge/wlight/)
|
||||
- [Forum](https://forum.minetest.net/viewtopic.php?t=26938)
|
||||
- [Git repo](https://github.com/AntumMT/mod-wlight)
|
||||
- [API](https://antummt.github.io/mod-wlight/docs/api.html)
|
||||
- [Changelog](changelog.txt)
|
||||
- [TODO](TODO.txt)
|
||||
- Echo's *walking_light*:
|
||||
- [Forum][forum.echo]
|
||||
- [v0.6 release](https://github.com/AntumMT/mod-wlight/releases/tag/v0.6)
|
||||
- petermaloney's *walking_light*:
|
||||
- [Git repo](https://github.com/petermaloney/walking_light)
|
||||
|
||||
**Alternative Mods:**
|
||||
|
||||
- [](https://content.minetest.net/packages/bell07/wielded_light/)
|
||||
|
||||
|
||||
[forum.echo]: https://forum.minetest.net/viewtopic.php?t=2621
|
@ -1,4 +0,0 @@
|
||||
|
||||
TODO:
|
||||
- wlight_debug should only enable debugging for player invoking command
|
||||
- use spherical area when calculating radius for chat commands
|
@ -1,636 +0,0 @@
|
||||
|
||||
--- wlight Methods
|
||||
--
|
||||
-- @topic methods
|
||||
|
||||
|
||||
-- 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 wlight_debug = false
|
||||
|
||||
-- name of light node, changed by toggling debug mode
|
||||
wlight_node = nil
|
||||
|
||||
--- Sets debugging mode.
|
||||
--
|
||||
-- @tparam bool enabled Determines if debugging is enabled.
|
||||
function wlight.set_debug(enabled)
|
||||
wlight_debug = enabled
|
||||
end
|
||||
|
||||
--- Checks if debugging is enabled.
|
||||
--
|
||||
-- @treturn bool
|
||||
function wlight.debug_enabled()
|
||||
return wlight_debug == true
|
||||
end
|
||||
|
||||
-- list of items that use walking light when wielded
|
||||
local light_items = {}
|
||||
|
||||
-- list of items that use walking light when equipped as armor
|
||||
local light_armor = {}
|
||||
|
||||
--- Registers an item to emit light when wielded.
|
||||
--
|
||||
-- @tparam string iname Item technical name.
|
||||
-- @tparam[opt] int radius Distance light will reach (max: 10).
|
||||
function wlight.register_item(iname, radius)
|
||||
if radius and radius > 10 then
|
||||
wlight.log("warning", "light radius too high, setting to 10")
|
||||
radius = 10
|
||||
end
|
||||
|
||||
local def = {radius=radius}
|
||||
|
||||
for li in pairs(light_items) do
|
||||
if iname == li then
|
||||
wlight.log("warning", "\"" .. iname .. "\" is already light item.")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
light_items[iname] = def
|
||||
end
|
||||
|
||||
--- DEPRECATED
|
||||
--
|
||||
-- Use `wlight.register_item`
|
||||
function wlight.addLightItem(item)
|
||||
wlight.log("warning",
|
||||
"\"wlight.addLightItem\" is deprecated, use \"wlight.register_item\"")
|
||||
|
||||
return wlight.register_item(item)
|
||||
end
|
||||
|
||||
--- Registers an item to emit light when equipped in armor inventory.
|
||||
--
|
||||
-- Note: light radius will be overridden by light-emitting item being wielded.
|
||||
--
|
||||
-- @tparam string iname Item technical name.
|
||||
-- @tparam[opt] int radius Distance light will reach (max: 10).
|
||||
-- @tparam[opt] bool litem Whether or not this item should also be registered with `wlight.register_item`.
|
||||
function wlight.register_armor(iname, radius, litem)
|
||||
if radius and radius > 10 then
|
||||
wlight.log("warning", "light radius too high, setting to 10")
|
||||
radius = 10
|
||||
end
|
||||
|
||||
local def = {radius=radius}
|
||||
if litem == nil then litem = true end
|
||||
|
||||
for la in pairs(light_armor) do
|
||||
if iname == la then
|
||||
wlight.log("warning", "\"" .. iname .. "\" is already light armor.")
|
||||
end
|
||||
end
|
||||
|
||||
light_armor[iname] = def
|
||||
if litem then wlight.register_item(iname, radius) end
|
||||
end
|
||||
|
||||
--- Retrieves list of items registered as emitting light when wielded.
|
||||
--
|
||||
-- @treturn table Table indexed by key.
|
||||
function wlight.get_light_items()
|
||||
return light_items
|
||||
end
|
||||
|
||||
--- DEPRECATED
|
||||
--
|
||||
-- Use `wlight.get_light_items`
|
||||
function wlight.getLightItems()
|
||||
wlight.log("warning",
|
||||
"\"wlight.getLightItems\" is deprecated, use \"wlight.get_light_items\"")
|
||||
|
||||
return wlight.get_light_items()
|
||||
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
|
||||
wlight.log("error", "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
|
||||
|
||||
--- Adds a node to the world.
|
||||
--
|
||||
-- @tparam table pos Position.
|
||||
-- @tparam table sometable
|
||||
function wlight.mt_add_node(pos, sometable)
|
||||
if pos == nil then
|
||||
wlight.log("error", "wlight.mt_add_node(), pos is nil")
|
||||
print(debug.traceback("Current Callstack:\n"))
|
||||
return nil
|
||||
end
|
||||
if sometable == nil then
|
||||
wlight.log("error", "wlight.mt_add_node(), sometable is nil")
|
||||
print(debug.traceback("Current Callstack:\n"))
|
||||
return nil
|
||||
end
|
||||
|
||||
core.add_node(pos, sometable)
|
||||
end
|
||||
|
||||
--- DEPRECATED
|
||||
--
|
||||
-- Use `wlight.mt_add_node`
|
||||
function mt_add_node(pos, sometable)
|
||||
wlight.log("warning", "\"mt_add_node\" is deprecated, use \"wlight.mt_add_node\"")
|
||||
|
||||
return wlight.mt_add_node(pos, sometable)
|
||||
end
|
||||
|
||||
local function round(num)
|
||||
return math.floor(num + 0.5)
|
||||
end
|
||||
|
||||
---
|
||||
--
|
||||
-- @tparam table pos1
|
||||
-- @tparam table pos2
|
||||
-- @treturn bool
|
||||
function wlight.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
|
||||
|
||||
--- DEPRECATED
|
||||
--
|
||||
-- Use `wlight.poseq`
|
||||
function poseq(pos1, pos2)
|
||||
wlight.log("warning", "\"poseq\" is deprecated, use \"wlight.poseq\"")
|
||||
|
||||
return wlight.poseq(pos1, pos2)
|
||||
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 wlight.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 wlight.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 wlight.poseq(pos, remove_pos) then
|
||||
table.remove(t, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- same as t[remove_pos], but uses wlight.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 wlight.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 == "wlight:light" or node.name == "wlight:light_debug") then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- Removes light at the given position.
|
||||
--
|
||||
-- @tparam[opt] ObjectRef player
|
||||
-- @tparam table pos Posistion where light will be removed.
|
||||
function wlight.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
|
||||
wlight.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
|
||||
wlight.log("warning", "wlight.remove_light(), pos = "
|
||||
.. dumppos(pos) .. ", tried to remove light but node was " .. node.name)
|
||||
table_remove_pos(light_positions[player_name], pos)
|
||||
else
|
||||
wlight.log("warning", "wlight.remove_light(), pos = "
|
||||
.. dumppos(pos) .. ", tried to remove light but node was nil")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- DEPRECATED
|
||||
--
|
||||
-- Use `wlight.remove_light`
|
||||
function remove_light(player, pos)
|
||||
wlight.log("warning", "\"remove_light\" is deprecated, use \"wlight.remove_light\"")
|
||||
|
||||
return wlight.remove_light(player, pos)
|
||||
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
|
||||
wlight.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, radius)
|
||||
local ret = {}
|
||||
if can_add_light(pos) then
|
||||
table.insert(ret, pos)
|
||||
end
|
||||
|
||||
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)
|
||||
local 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(player, pos, radius)
|
||||
if radius then
|
||||
return pick_light_position_radius(player, pos, radius)
|
||||
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
|
||||
wlight.mt_add_node(pos, {type="node", name=wlight_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
|
||||
|
||||
-- returns a string, the name of the item found that is a light item
|
||||
local function get_wielded_light_item(player)
|
||||
local wielded_item = player:get_wielded_item():get_name()
|
||||
if wielded_item ~= "" and wlight.is_light_item(wielded_item) then
|
||||
return wielded_item
|
||||
end
|
||||
|
||||
-- check equipped armor
|
||||
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
|
||||
for k, stack in pairs(armor_inv:get_list("armor")) do
|
||||
local item_name = stack:get_name()
|
||||
if wlight.is_light_armor(item_name) then
|
||||
return item_name, true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
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, is_armor = 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
|
||||
local radius
|
||||
if is_armor then
|
||||
radius = light_armor[wielded_item].radius
|
||||
else
|
||||
radius = light_items[wielded_item].radius
|
||||
end
|
||||
|
||||
-- decide where light should be
|
||||
wantlightpos = pick_light_position(player, wantpos, radius)
|
||||
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
|
||||
wlight.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
|
||||
|
||||
--- Checks if an item is registered as emitting light when wielded.
|
||||
--
|
||||
-- @tparam string iname Item technical name.
|
||||
-- @treturn bool `true` if item is registered.
|
||||
function wlight.is_light_item(iname)
|
||||
for li in pairs(light_items) do
|
||||
if iname == li then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--- Checks if an item is registered as emitting light when equipped in armor inventory.
|
||||
--
|
||||
-- @tparam string iname Item technical name.
|
||||
-- @treturn bool `true` if item is registered.
|
||||
function wlight.is_light_armor(iname)
|
||||
for la in pairs(light_armor) do
|
||||
if iname == la then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--- Checks if player is wielding a light-emitting item.
|
||||
--
|
||||
-- @tparam ObjectRef player Player to be checked.
|
||||
-- @treturn bool `true` if player is wielding registered item.
|
||||
function wlight.wields_light(player)
|
||||
return 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] = 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)
|
||||
|
||||
--- Updates light node texture.
|
||||
--
|
||||
-- If debugging, node will display a marker, otherwise will be transparent.
|
||||
function wlight.update_node()
|
||||
if wlight_debug then
|
||||
wlight_node = "wlight:light_debug"
|
||||
else
|
||||
wlight_node = "wlight:light"
|
||||
end
|
||||
end
|
||||
|
||||
wlight.update_node()
|
@ -1,30 +0,0 @@
|
||||
|
||||
v1.0
|
||||
----
|
||||
- forked from petermaloney @ Git commit 766ef0f ( https://github.com/petermaloney/walking_light/tree/766ef0f )
|
||||
- changed code license to MIT
|
||||
- added mod.conf
|
||||
- re-created underlay image
|
||||
- some code cleanup & optimization
|
||||
- hand is not checked for light
|
||||
- added global method for registering an armor item
|
||||
- segregated code into modules
|
||||
- removed walking_light:pick_mese & walking_light:helmet_diamond (mods should register their own light items)
|
||||
- megatorch can be disabled via setting
|
||||
- added localization support
|
||||
- added option to set custom light radius when registering item or armor
|
||||
- removed method "walking_light.register_tool"
|
||||
- renamed to "wlight"
|
||||
- consolidated chat commands into single "wlight" command
|
||||
- fixed "/wlight add" command not able to illuminate more than one node
|
||||
|
||||
petermaloney
|
||||
------------
|
||||
- forked from walking_light v0.6 by Echo ( https://forum.minetest.net/viewtopic.php?t=2621 )
|
||||
- bug fixes & code optimizations
|
||||
- light updated on player login
|
||||
- added 3d_armor support
|
||||
- added items walking_light:helmet_diamond & walking_light:megatorch
|
||||
- added global method for registering items for use with walking_light
|
||||
- replaced deprecated methods & parameters
|
||||
- prefixed chat commands with "walking_light"
|
@ -1,103 +0,0 @@
|
||||
|
||||
--- wlight Chat Commands
|
||||
--
|
||||
-- @topic commands
|
||||
|
||||
|
||||
local S = core.get_translator(wlight.modname)
|
||||
|
||||
|
||||
--- Manages lighted nodes and debugging.
|
||||
--
|
||||
-- **Parameters:**
|
||||
--
|
||||
-- @chatcmd wlight
|
||||
-- @tparam command Command action to be executed.
|
||||
-- @tparam[opt] radius Area radius (default: 20).
|
||||
-- @usage /wlight <command> [radius]
|
||||
--
|
||||
-- Commands:
|
||||
-- - add: Add lighting to current position.
|
||||
-- - remove: Remove lighting from current position.
|
||||
-- - debug: Toggle illuminated nodes visible mark for debugging.
|
||||
--
|
||||
-- Options:
|
||||
-- - radius: Area radius (add default: 0, remove default: 20).
|
||||
--
|
||||
-- Example:
|
||||
-- /wlight add 5
|
||||
core.register_chatcommand(wlight.modname, {
|
||||
params = "<" .. S("command") .. "> [" .. S("radius") .. "]",
|
||||
privs = {server=true},
|
||||
description = S("Manage lighted nodes and debugging.")
|
||||
.. "\n\n" .. S("Commands:")
|
||||
.. "\n add: " .. S("Add lighting to current position.")
|
||||
.. "\n remove: " .. S("Remove lighting from current position.")
|
||||
.. "\n debug: " .. S("Toggle illuminated nodes visible mark for debugging.")
|
||||
.. "\n\n" .. S("Options:")
|
||||
.. "\n " .. S("radius") .. ": " .. S("Area radius (add default: 0, remove default: 20)."),
|
||||
func = function(name, param)
|
||||
local command
|
||||
local radius
|
||||
if param:find(" ") then
|
||||
local params = param:split(" ")
|
||||
command = params[1]
|
||||
radius = tonumber(params[2])
|
||||
else
|
||||
command = param
|
||||
end
|
||||
|
||||
if not radius then
|
||||
radius = 0
|
||||
if command == "remove" then
|
||||
radius = 20
|
||||
end
|
||||
end
|
||||
|
||||
if command == "" then
|
||||
core.chat_send_player(name, "\n" .. S("Missing command parameter."))
|
||||
return false
|
||||
end
|
||||
|
||||
if (command == "add" or command == "remove") and not radius then
|
||||
core.chat_send_player(name, "\n" .. S("Missing radius parameter."))
|
||||
return false
|
||||
end
|
||||
|
||||
local pos = vector.round(core.get_player_by_name(name):get_pos())
|
||||
|
||||
if command == "debug" then
|
||||
wlight.set_debug(not wlight.debug_enabled())
|
||||
wlight.update_node()
|
||||
elseif command == "add" then
|
||||
pos = vector.new(pos.x, pos.y + 1, pos.z)
|
||||
if pos then
|
||||
local pmin = {x=pos.x-radius, y=pos.y-radius, z=pos.z-radius}
|
||||
local pmax = {x=pos.x+radius, y=pos.y+radius, z=pos.z+radius}
|
||||
local near_nodes = core.find_nodes_in_area(pmin, pmax, "air", true)
|
||||
if near_nodes.air then
|
||||
for _, npos in ipairs(near_nodes.air) do
|
||||
wlight.mt_add_node(npos, {type="node", name=wlight_node})
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif command == "remove" then
|
||||
for _, v in ipairs({"wlight:light", "wlight:light_debug"}) do
|
||||
local point = core.find_node_near(pos, radius, v)
|
||||
while point do
|
||||
wlight.remove_light(nil, point)
|
||||
local oldpoint = point
|
||||
point = core.find_node_near(pos, radius, v)
|
||||
if wlight.poseq(oldpoint, point) then
|
||||
return false, S("Failed... infinite loop detected.")
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
core.chat_send_player(name, "\n" .. S("Unknown command: @1", command))
|
||||
return false
|
||||
end
|
||||
|
||||
return true, S("Done.")
|
||||
end,
|
||||
})
|
@ -1,38 +0,0 @@
|
||||
|
||||
wlight = {}
|
||||
wlight.modname = core.get_current_modname()
|
||||
wlight.modpath = core.get_modpath(wlight.modname)
|
||||
|
||||
-- override walking_light
|
||||
walking_light = wlight
|
||||
|
||||
function wlight.log(lvl, msg)
|
||||
if not msg then
|
||||
msg = lvl
|
||||
lvl = nil
|
||||
end
|
||||
|
||||
msg = "[" .. wlight.modname .. "] " .. msg
|
||||
if not lvl then
|
||||
core.log(msg)
|
||||
else
|
||||
core.log(lvl, msg)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local scripts = {
|
||||
"settings",
|
||||
"api",
|
||||
"chat",
|
||||
"nodes",
|
||||
}
|
||||
|
||||
for _, sc in ipairs(scripts) do
|
||||
dofile(wlight.modpath .. "/" .. sc .. ".lua")
|
||||
end
|
||||
|
||||
|
||||
if core.registered_items["default:torch"] then
|
||||
wlight.register_item("default:torch")
|
||||
end
|
@ -1,20 +0,0 @@
|
||||
Translated by:
|
||||
|
||||
|
||||
# chat.lua
|
||||
Manage lighted nodes and debugging.=
|
||||
Commands:=
|
||||
Options:=
|
||||
command=
|
||||
radius=
|
||||
Missing command parameter.=
|
||||
Missing radius parameter.=
|
||||
Add lighting to current position.=
|
||||
Remove lighting from current position.=
|
||||
Toggle illuminated nodes visible mark for debugging.=
|
||||
Area radius (add default: 0, remove default: 20).=
|
||||
Failed... infinite loop detected.=
|
||||
Done.=
|
||||
|
||||
# nodes.lua
|
||||
Megatorch=
|
@ -1,5 +0,0 @@
|
||||
name = wlight
|
||||
description = Adds items that will illuminate area around player when wielded or equipped.
|
||||
version = 1.0
|
||||
author = Echo, petermaloney, Jordan Irwin (AntumDeluge)
|
||||
optional_depends = default, walking_light
|
@ -1,100 +0,0 @@
|
||||
|
||||
local S = core.get_translator(wlight.modname)
|
||||
|
||||
|
||||
core.register_node("wlight:light_debug", {
|
||||
drawtype = "plantlike",
|
||||
tiles = {"wlight_inv_underlay.png"},
|
||||
inventory_image = core.inventorycube("wlight_inv_underlay.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_alias("walking_light:light_debug", "wlight:light_debug")
|
||||
|
||||
core.register_node("wlight:light", {
|
||||
drawtype = "glasslike",
|
||||
tiles = {"wlight_light.png"},
|
||||
inventory_image = core.inventorycube("wlight_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_alias("walking_light:light", "wlight:light")
|
||||
|
||||
if wlight.enable_megatorch and core.get_modpath("default") then
|
||||
core.register_node("wlight:megatorch", {
|
||||
description = S("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,
|
||||
})
|
||||
|
||||
wlight.register_item("wlight:megatorch", 10)
|
||||
|
||||
core.register_craft({
|
||||
output = "wlight:megatorch",
|
||||
recipe = {
|
||||
{"default:torch", "default:torch", "default:torch"},
|
||||
{"default:torch", "default:torch", "default:torch"},
|
||||
{"default:torch", "default:torch", "default:torch"},
|
||||
}
|
||||
})
|
||||
|
||||
core.register_alias("walking_light:megatorch", "wlight:megatorch")
|
||||
end
|
Binary file not shown.
Before Width: | Height: | Size: 283 KiB |
@ -1,12 +0,0 @@
|
||||
|
||||
--- wlight Settings
|
||||
--
|
||||
-- @topic settings
|
||||
|
||||
|
||||
--- Enables wlight:megatorch item.
|
||||
--
|
||||
-- @setting wlight.enable_megatorch
|
||||
-- @settype bool
|
||||
-- @default true
|
||||
wlight.enable_megatorch = core.settings:get_bool("wlight.enable_megatorch", true)
|
@ -1,3 +0,0 @@
|
||||
|
||||
# Enables wlight:megatorch item.
|
||||
wlight.enable_megatorch (Enable megatorch) bool true
|
Binary file not shown.
Before Width: | Height: | Size: 174 B |
Binary file not shown.
Before Width: | Height: | Size: 128 B |
@ -2115,12 +2115,6 @@ slingshot.ammos (Registered ammos) string default:mese_crystal=5
|
||||
trampoline.damage_absorb (Trampoline damage absorption) int 100 0 100
|
||||
|
||||
|
||||
[*wlight]
|
||||
|
||||
# Enables wlight:megatorch item.
|
||||
wlight.enable_megatorch (Enable megatorch) bool true
|
||||
|
||||
|
||||
[*wardrobe]
|
||||
|
||||
# Number of skins shown per page.
|
||||
|
Loading…
x
Reference in New Issue
Block a user