Start refactor

This commit is contained in:
teknomunk 2024-05-27 08:04:22 +00:00
parent 026ea5940c
commit 5d81204fc8

@ -1,10 +1,11 @@
local mods_loaded = false -- Constants
local NIGHT_VISION_RATIO = 0.45 local NIGHT_VISION_RATIO = 0.45
local MINIMUM_LIGHT_LEVEL = 0.2 local MINIMUM_LIGHT_LEVEL = 0.2
local DEFAULT_WATER_COLOR = "#3F76E4"
local water_color = "#3F76E4" -- Module state
local mods_loaded = false
local water_color = DEFAULT_WATER_COLOR
local mg_name = minetest.get_mapgen_setting("mg_name") local mg_name = minetest.get_mapgen_setting("mg_name")
function mcl_weather.set_sky_box_clear(player, sky, fog) function mcl_weather.set_sky_box_clear(player, sky, fog)
@ -65,7 +66,7 @@ local function get_light_modifier(time)
return light_multiplier return light_multiplier
end end
mcl_weather.skycolor = { local skycolor = {
-- Should be activated before do any effect. -- Should be activated before do any effect.
active = true, active = true,
@ -88,287 +89,305 @@ mcl_weather.skycolor = {
-- Table for tracking layer order -- Table for tracking layer order
layer_names = {}, layer_names = {},
-- To layer to colors table utils = {},
add_layer = function(layer_name, layer_color, instant_update) }
mcl_weather.skycolor.colors[layer_name] = layer_color mcl_weather.skycolor = skycolor
table.insert(mcl_weather.skycolor.layer_names, layer_name) local skycolor_utils = skycolor.utils
mcl_weather.skycolor.force_update = true
end,
current_layer_name = function() -- To layer to colors table
return mcl_weather.skycolor.layer_names[#mcl_weather.skycolor.layer_names] function skycolor.add_layer(layer_name, layer_color, instant_update)
end, mcl_weather.skycolor.colors[layer_name] = layer_color
table.insert(mcl_weather.skycolor.layer_names, layer_name)
mcl_weather.skycolor.force_update = true
end
-- Retrieve layer from colors table function skycolor.current_layer_name()
retrieve_layer = function() return mcl_weather.skycolor.layer_names[#mcl_weather.skycolor.layer_names]
local last_layer = mcl_weather.skycolor.current_layer_name() end
return mcl_weather.skycolor.colors[last_layer]
end,
-- Remove layer from colors table -- Retrieve layer from colors table
remove_layer = function(layer_name) function skycolor.retrieve_layer()
for k, name in pairs(mcl_weather.skycolor.layer_names) do local last_layer = mcl_weather.skycolor.current_layer_name()
if name == layer_name then return mcl_weather.skycolor.colors[last_layer]
table.remove(mcl_weather.skycolor.layer_names, k) end
mcl_weather.skycolor.force_update = true
return -- Remove layer from colors table
end function skycolor.remove_layer(layer_name)
for k, name in pairs(mcl_weather.skycolor.layer_names) do
if name == layer_name then
table.remove(mcl_weather.skycolor.layer_names, k)
mcl_weather.skycolor.force_update = true
return
end end
end, end
end
-- Wrapper for updating day/night ratio that respects night vision -- Wrapper for updating day/night ratio that respects night vision
override_day_night_ratio = function(player, ratio) function skycolor.override_day_night_ratio(player, ratio)
local meta = player:get_meta() local meta = player:get_meta()
local has_night_vision = meta:get_int("night_vision") == 1 local has_night_vision = meta:get_int("night_vision") == 1
local has_darkness = meta:get_int("darkness") == 1 local has_darkness = meta:get_int("darkness") == 1
local is_visited_shepherd = meta:get_int("mcl_shepherd:special") == 1 local is_visited_shepherd = meta:get_int("mcl_shepherd:special") == 1
local arg local arg
if has_darkness and not is_visited_shepherd then if has_darkness and not is_visited_shepherd then
if has_night_vision then arg = 0.1 if has_night_vision then arg = 0.1
else arg = 0 end else arg = 0 end
else else
-- Apply night vision only for dark sky -- Apply night vision only for dark sky
local is_dark = minetest.get_timeofday() > 0.8 or minetest.get_timeofday() < 0.2 or mcl_weather.state ~= "none" local is_dark = minetest.get_timeofday() > 0.8 or minetest.get_timeofday() < 0.2 or mcl_weather.state ~= "none"
local pos = player:get_pos() local pos = player:get_pos()
local dim = mcl_worlds.pos_to_dimension(pos) local dim = mcl_worlds.pos_to_dimension(pos)
if (has_night_vision or is_visited_shepherd) and is_dark and dim ~= "nether" and dim ~= "end" then if (has_night_vision or is_visited_shepherd) and is_dark and dim ~= "nether" and dim ~= "end" then
if ratio == nil then if ratio == nil then
arg = NIGHT_VISION_RATIO arg = NIGHT_VISION_RATIO
else
arg = math.max(ratio, NIGHT_VISION_RATIO)
end
else else
arg = ratio arg = math.max(ratio, NIGHT_VISION_RATIO)
end end
else
arg = ratio
end end
player:override_day_night_ratio(arg) end
end, player:override_day_night_ratio(arg)
end
-- Update sky color. If players not specified update sky for all players. function water_sky(player)
update_sky_color = function(players) local pos = player:get_pos()
-- Override day/night ratio as well local water_color = DEFAULT_WATER_COLOR
players = mcl_weather.skycolor.utils.get_players(players)
for _, player in ipairs(players) do local checkname = minetest.get_node(vector.new(pos.x,pos.y+1.5,pos.z)).name
local pos = player:get_pos() if minetest.get_item_group(checkname, "water") == 0 then return end
local dim = mcl_worlds.pos_to_dimension(pos)
local has_weather = (mcl_worlds.has_weather(pos) and (mcl_weather.state == "snow" or mcl_weather.state =="rain" or mcl_weather.state == "thunder") and mcl_weather.has_snow(pos)) or ((mcl_weather.state =="rain" or mcl_weather.state == "thunder") and mcl_weather.has_rain(pos)) local biome_index = minetest.get_biome_data(player:get_pos()).biome
local checkname = minetest.get_node(vector.new(pos.x,pos.y+1.5,pos.z)).name local biome_name = minetest.get_biome_name(biome_index)
if minetest.get_item_group(checkname, "water") ~= 0 then local biome = minetest.registered_biomes[biome_name]
if biome then water_color = biome._mcl_waterfogcolor end
if not biome then water_color = "#3F76E4" end
if checkname == "mclx_core:river_water_source" or checkname == "mclx_core:river_water_flowing" then water_color = "#0084FF" end
return {
sky = { type = "regular",
sky_color = {
day_sky = water_color,
day_horizon = water_color,
dawn_sky = water_color,
dawn_horizon = water_color,
night_sky = water_color,
night_horizon = water_color,
indoors = water_color,
fog_sun_tint = water_color,
fog_moon_tint = water_color,
fog_tint_type = "custom"
},
clouds = false,
}
}
end
-- Update sky color. If players not specified update sky for all players.
function skycolor.update_sky_color(players)
-- Override day/night ratio as well
players = mcl_weather.skycolor.utils.get_players(players)
for _, player in ipairs(players) do
local pos = player:get_pos()
local dim = mcl_worlds.pos_to_dimension(pos)
local has_weather = (mcl_worlds.has_weather(pos) and (mcl_weather.state == "snow" or mcl_weather.state =="rain" or mcl_weather.state == "thunder") and mcl_weather.has_snow(pos)) or ((mcl_weather.state =="rain" or mcl_weather.state == "thunder") and mcl_weather.has_rain(pos))
local res = water_sky(player)
if res and res.sky then
player:set_sky(res.sky)
end
if dim == "overworld" then
local biomesky
local biomefog
if mg_name ~= "v6" and mg_name ~= "singlenode" then
local biome_index = minetest.get_biome_data(player:get_pos()).biome local biome_index = minetest.get_biome_data(player:get_pos()).biome
local biome_name = minetest.get_biome_name(biome_index) local biome_name = minetest.get_biome_name(biome_index)
local biome = minetest.registered_biomes[biome_name] local biome = minetest.registered_biomes[biome_name]
if biome then water_color = biome._mcl_waterfogcolor end if biome then
if not biome then water_color = "#3F76E4" end --minetest.log("action", string.format("Biome found for number: %s in biome: %s", tostring(biome_index), biome_name))
if checkname == "mclx_core:river_water_source" or checkname == "mclx_core:river_water_flowing" then water_color = "#0084FF" end biomesky = biome._mcl_skycolor
player:set_sky({ type = "regular", biomefog = biome._mcl_fogcolor
sky_color = { else
day_sky = water_color, --minetest.log("action", string.format("No biome for number: %s in biome: %s", tostring(biome_index), biome_name))
day_horizon = water_color, end
dawn_sky = water_color,
dawn_horizon = water_color,
night_sky = water_color,
night_horizon = water_color,
indoors = water_color,
fog_sun_tint = water_color,
fog_moon_tint = water_color,
fog_tint_type = "custom"
},
clouds = false,
})
end end
if dim == "overworld" then if (mcl_weather.state == "none") then
local biomesky -- Clear weather
local biomefog mcl_weather.set_sky_box_clear(player,biomesky,biomefog)
if mg_name ~= "v6" and mg_name ~= "singlenode" then player:set_sun({visible = true, sunrise_visible = true})
local biome_index = minetest.get_biome_data(player:get_pos()).biome player:set_moon({visible = true})
local biome_name = minetest.get_biome_name(biome_index) player:set_stars({visible = true})
local biome = minetest.registered_biomes[biome_name] mcl_weather.skycolor.override_day_night_ratio(player, nil)
if biome then elseif not has_weather then
--minetest.log("action", string.format("Biome found for number: %s in biome: %s", tostring(biome_index), biome_name)) local day_color = mcl_weather.skycolor.get_sky_layer_color(0.15)
biomesky = biome._mcl_skycolor local dawn_color = mcl_weather.skycolor.get_sky_layer_color(0.27)
biomefog = biome._mcl_fogcolor local night_color = mcl_weather.skycolor.get_sky_layer_color(0.1)
else
--minetest.log("action", string.format("No biome for number: %s in biome: %s", tostring(biome_index), biome_name))
end
end
if (mcl_weather.state == "none") then
-- Clear weather
mcl_weather.set_sky_box_clear(player,biomesky,biomefog)
player:set_sun({visible = true, sunrise_visible = true})
player:set_moon({visible = true})
player:set_stars({visible = true})
mcl_weather.skycolor.override_day_night_ratio(player, nil)
elseif not has_weather then
local day_color = mcl_weather.skycolor.get_sky_layer_color(0.15)
local dawn_color = mcl_weather.skycolor.get_sky_layer_color(0.27)
local night_color = mcl_weather.skycolor.get_sky_layer_color(0.1)
mcl_weather.set_sky_color(player, {
type = "regular",
sky_color = {
day_sky = day_color,
day_horizon = day_color,
dawn_sky = dawn_color,
dawn_horizon = dawn_color,
night_sky = night_color,
night_horizon = night_color,
},
clouds = true,
})
player:set_sun({visible = false, sunrise_visible = false})
player:set_moon({visible = false})
player:set_stars({visible = false})
elseif has_weather then
-- Weather skies
local day_color = mcl_weather.skycolor.get_sky_layer_color(0.5)
local dawn_color = mcl_weather.skycolor.get_sky_layer_color(0.75)
local night_color = mcl_weather.skycolor.get_sky_layer_color(0)
mcl_weather.set_sky_color(player, {
type = "regular",
sky_color = {
day_sky = day_color,
day_horizon = day_color,
dawn_sky = dawn_color,
dawn_horizon = dawn_color,
night_sky = night_color,
night_horizon = night_color,
},
clouds = true,
})
player:set_sun({visible = false, sunrise_visible = false})
player:set_moon({visible = false})
player:set_stars({visible = false})
local light_factor = mcl_weather.get_current_light_factor()
if mcl_weather.skycolor.current_layer_name() == "lightning" then
mcl_weather.skycolor.override_day_night_ratio(player, 1)
elseif light_factor then
local time = minetest.get_timeofday()
local light_multiplier = get_light_modifier(time)
local new_light = math.max(light_factor * light_multiplier, MINIMUM_LIGHT_LEVEL)
mcl_weather.skycolor.override_day_night_ratio(player, new_light)
else
mcl_weather.skycolor.override_day_night_ratio(player, nil)
end
end
elseif dim == "end" then
local biomesky = "#000000"
local biomefog = "#A080A0"
if mg_name ~= "v6" and mg_name ~= "singlenode" then
local biome_index = minetest.get_biome_data(player:get_pos()).biome
local biome_name = minetest.get_biome_name(biome_index)
local biome = minetest.registered_biomes[biome_name]
if biome then
--minetest.log("action", string.format("Biome found for number: %s in biome: %s", tostring(biome_index), biome_name))
biomesky = biome._mcl_skycolor
biomefog = biome._mcl_fogcolor -- The End biomes seemingly don't use the fog colour, despite having this value according to the wiki. The sky colour is seemingly used for both sky and fog?
else
--minetest.log("action", string.format("No biome for number: %s in biome: %s", tostring(biome_index), biome_name))
end
end
local t = "mcl_playerplus_end_sky.png"
player:set_sky({ type = "skybox",
base_color = biomesky,
textures = {t,t,t,t,t,t},
clouds = false,
})
player:set_sun({visible = false , sunrise_visible = false})
player:set_moon({visible = false})
player:set_stars({visible = false})
mcl_weather.skycolor.override_day_night_ratio(player, 0.5)
elseif dim == "nether" then
local biomesky = "#6EB1FF"
local biomefog = "#330808"
if mg_name ~= "v6" and mg_name ~= "singlenode" then
local biome_index = minetest.get_biome_data(player:get_pos()).biome
local biome_name = minetest.get_biome_name(biome_index)
local biome = minetest.registered_biomes[biome_name]
if biome then
--minetest.log("action", string.format("Biome found for number: %s in biome: %s", tostring(biome_index), biome_name))
biomesky = biome._mcl_skycolor -- The Nether biomes seemingly don't use the sky colour, despite having this value according to the wiki. The fog colour is used for both sky and fog.
biomefog = biome._mcl_fogcolor
else
--minetest.log("action", string.format("No biome for number: %s in biome: %s", tostring(biome_index), biome_name))
end
end
mcl_weather.set_sky_color(player, { mcl_weather.set_sky_color(player, {
type = "regular", type = "regular",
sky_color = { sky_color = {
day_sky = biomefog, day_sky = day_color,
day_horizon = biomefog, day_horizon = day_color,
dawn_sky = biomefog, dawn_sky = dawn_color,
dawn_horizon = biomefog, dawn_horizon = dawn_color,
night_sky = biomefog, night_sky = night_color,
night_horizon = biomefog, night_horizon = night_color,
indoors = biomefog,
fog_sun_tint = biomefog,
fog_moon_tint = biomefog,
fog_tint_type = "custom"
}, },
clouds = false, clouds = true,
}) })
player:set_sun({visible = false , sunrise_visible = false}) player:set_sun({visible = false, sunrise_visible = false})
player:set_moon({visible = false}) player:set_moon({visible = false})
player:set_stars({visible = false}) player:set_stars({visible = false})
mcl_weather.skycolor.override_day_night_ratio(player, nil) elseif has_weather then
elseif dim == "void" then -- Weather skies
player:set_sky({ type = "plain", local day_color = mcl_weather.skycolor.get_sky_layer_color(0.5)
base_color = "#000000", local dawn_color = mcl_weather.skycolor.get_sky_layer_color(0.75)
clouds = false, local night_color = mcl_weather.skycolor.get_sky_layer_color(0)
mcl_weather.set_sky_color(player, {
type = "regular",
sky_color = {
day_sky = day_color,
day_horizon = day_color,
dawn_sky = dawn_color,
dawn_horizon = dawn_color,
night_sky = night_color,
night_horizon = night_color,
},
clouds = true,
}) })
player:set_sun({visible = false, sunrise_visible = false}) player:set_sun({visible = false, sunrise_visible = false})
player:set_moon({visible = false}) player:set_moon({visible = false})
player:set_stars({visible = false}) player:set_stars({visible = false})
end
end
end,
-- Returns current layer color in {r, g, b} format local light_factor = mcl_weather.get_current_light_factor()
get_sky_layer_color = function(timeofday) if mcl_weather.skycolor.current_layer_name() == "lightning" then
if #mcl_weather.skycolor.layer_names == 0 then mcl_weather.skycolor.override_day_night_ratio(player, 1)
return nil elseif light_factor then
end local time = minetest.get_timeofday()
local light_multiplier = get_light_modifier(time)
-- min timeofday value 0; max timeofday value 1. So sky color gradient range will be between 0 and 1 * mcl_weather.skycolor.max_val. local new_light = math.max(light_factor * light_multiplier, MINIMUM_LIGHT_LEVEL)
local rounded_time = math.floor(timeofday * mcl_weather.skycolor.max_val) mcl_weather.skycolor.override_day_night_ratio(player, new_light)
local color = mcl_weather.skycolor.utils.convert_to_rgb(mcl_weather.skycolor.min_val, mcl_weather.skycolor.max_val, rounded_time, mcl_weather.skycolor.retrieve_layer()) else
return color mcl_weather.skycolor.override_day_night_ratio(player, nil)
end,
utils = {
convert_to_rgb = function(minval, maxval, current_val, colors)
local max_index = #colors - 1
local val = (current_val-minval) / (maxval-minval) * max_index + 1.0
local index1 = math.floor(val)
local index2 = math.min(math.floor(val)+1, max_index + 1)
local f = val - index1
local c1 = colors[index1]
local c2 = colors[index2]
return {r=math.floor(c1.r + f*(c2.r - c1.r)), g=math.floor(c1.g + f*(c2.g-c1.g)), b=math.floor(c1.b + f*(c2.b - c1.b))}
end,
-- Simply getter. Ether returns user given players list or get all connected players if none provided
get_players = function(players)
if players == nil or #players == 0 then
if mods_loaded then
players = minetest.get_connected_players()
elseif players == nil then
players = {}
end end
end end
return players elseif dim == "end" then
end, local biomesky = "#000000"
local biomefog = "#A080A0"
-- Returns first player sky color. I assume that all players are in same color layout. if mg_name ~= "v6" and mg_name ~= "singlenode" then
get_current_bg_color = function() local biome_index = minetest.get_biome_data(player:get_pos()).biome
local players = mcl_weather.skycolor.utils.get_players(nil) local biome_name = minetest.get_biome_name(biome_index)
if players[1] then local biome = minetest.registered_biomes[biome_name]
return players[1]:get_sky(true).sky_color if biome then
--minetest.log("action", string.format("Biome found for number: %s in biome: %s", tostring(biome_index), biome_name))
biomesky = biome._mcl_skycolor
biomefog = biome._mcl_fogcolor -- The End biomes seemingly don't use the fog colour, despite having this value according to the wiki. The sky colour is seemingly used for both sky and fog?
else
--minetest.log("action", string.format("No biome for number: %s in biome: %s", tostring(biome_index), biome_name))
end
end end
return nil local t = "mcl_playerplus_end_sky.png"
player:set_sky({ type = "skybox",
base_color = biomesky,
textures = {t,t,t,t,t,t},
clouds = false,
})
player:set_sun({visible = false , sunrise_visible = false})
player:set_moon({visible = false})
player:set_stars({visible = false})
mcl_weather.skycolor.override_day_night_ratio(player, 0.5)
elseif dim == "nether" then
local biomesky = "#6EB1FF"
local biomefog = "#330808"
if mg_name ~= "v6" and mg_name ~= "singlenode" then
local biome_index = minetest.get_biome_data(player:get_pos()).biome
local biome_name = minetest.get_biome_name(biome_index)
local biome = minetest.registered_biomes[biome_name]
if biome then
--minetest.log("action", string.format("Biome found for number: %s in biome: %s", tostring(biome_index), biome_name))
biomesky = biome._mcl_skycolor -- The Nether biomes seemingly don't use the sky colour, despite having this value according to the wiki. The fog colour is used for both sky and fog.
biomefog = biome._mcl_fogcolor
else
--minetest.log("action", string.format("No biome for number: %s in biome: %s", tostring(biome_index), biome_name))
end
end
mcl_weather.set_sky_color(player, {
type = "regular",
sky_color = {
day_sky = biomefog,
day_horizon = biomefog,
dawn_sky = biomefog,
dawn_horizon = biomefog,
night_sky = biomefog,
night_horizon = biomefog,
indoors = biomefog,
fog_sun_tint = biomefog,
fog_moon_tint = biomefog,
fog_tint_type = "custom"
},
clouds = false,
})
player:set_sun({visible = false , sunrise_visible = false})
player:set_moon({visible = false})
player:set_stars({visible = false})
mcl_weather.skycolor.override_day_night_ratio(player, nil)
elseif dim == "void" then
player:set_sky({ type = "plain",
base_color = "#000000",
clouds = false,
})
player:set_sun({visible = false, sunrise_visible = false})
player:set_moon({visible = false})
player:set_stars({visible = false})
end end
}, end
end -- END function skycolor.update_sky_color(players)
} -- Returns current layer color in {r, g, b} format
function skycolor.get_sky_layer_color(timeofday)
if #mcl_weather.skycolor.layer_names == 0 then
return nil
end
-- min timeofday value 0; max timeofday value 1. So sky color gradient range will be between 0 and 1 * mcl_weather.skycolor.max_val.
local rounded_time = math.floor(timeofday * mcl_weather.skycolor.max_val)
local color = mcl_weather.skycolor.utils.convert_to_rgb(mcl_weather.skycolor.min_val, mcl_weather.skycolor.max_val, rounded_time, mcl_weather.skycolor.retrieve_layer())
return color
end
function skycolor_utils.convert_to_rgb(minval, maxval, current_val, colors)
local max_index = #colors - 1
local val = (current_val-minval) / (maxval-minval) * max_index + 1.0
local index1 = math.floor(val)
local index2 = math.min(math.floor(val)+1, max_index + 1)
local f = val - index1
local c1 = colors[index1]
local c2 = colors[index2]
return {r=math.floor(c1.r + f*(c2.r - c1.r)), g=math.floor(c1.g + f*(c2.g-c1.g)), b=math.floor(c1.b + f*(c2.b - c1.b))}
end
-- Simply getter. Ether returns user given players list or get all connected players if none provided
function skycolor_utils.get_players(players)
if players == nil or #players == 0 then
if mods_loaded then
players = minetest.get_connected_players()
elseif players == nil then
players = {}
end
end
return players
end
-- Returns first player sky color. I assume that all players are in same color layout.
function skycolor_utils.get_current_bg_color()
local players = mcl_weather.skycolor.utils.get_players(nil)
if players[1] then
return players[1]:get_sky(true).sky_color
end
return nil
end
local timer = 0 local timer = 0
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)