diff --git a/README.md b/README.md index 4860b09..d4d298b 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,7 @@ Make sure you have the latest version installed or [update your game](https://ww ## Dependencies This mod has no hard dependencies whatsoever, so you can use it as you will. -However, I do recommend using the [skylayer](https://gitlab.com/rautars/skylayer) mod. -With the Minetest's new sky API it is likely for more mods to change the sky configuration, -possibly resulting in conflict. This utility mod can help circumvent these issues if both mods use it. +If you are also using *climate_api* then it will use the included skybox registration instead of overriding the player configuration. Thus, moon_phases will will be compatible with your weather packs. ## Commands This mod comes with two commands to print or change the current moon phase. diff --git a/ca_weathers/moon_phases.lua b/ca_weathers/moon_phases.lua new file mode 100644 index 0000000..4645873 --- /dev/null +++ b/ca_weathers/moon_phases.lua @@ -0,0 +1,106 @@ +local name = "moon_phases:phase" +local mod_climate_api = minetest.get_modpath("climate_api") ~= nil + +local GSCYCLE = 0.5 -- global step cycle +local DEFAULT_LENGTH = 4 -- default cycle length +local DEFAULT_STYLE = "realistic" -- default texture style +local PHASE_COUNT = 8 -- number of phases to go through + +-- retrieve mod configuration +local PHASE_LENGTH = minetest.settings:get("moon_phases_cycle") or DEFAULT_LENGTH +local TEXTURE_STYLE = minetest.settings:get("moon_phases_style") or DEFAULT_STYLE + +local moon_phases = {} +local state = minetest.get_mod_storage() +local phase = 1 + +-- return the current moon phase +function moon_phases.get_phase() + return phase +end + +-- set the current moon phase +-- @param phase int Phase between 1 and PHASE_COUNT +function moon_phases.set_phase(nphase) + phase = math.floor(tonumber(nphase)) + if (not nphase) or nphase < 1 or nphase > PHASE_COUNT then + return false + end + local day = params.day_count + local date_offset = state:get_int("date_offset") + local progress = (day + date_offset - 1) % PHASE_LENGTH + 1 + local phase_offset = (nphase - phase + PHASE_COUNT) % PHASE_COUNT + local add_offset = (phase_offset * PHASE_LENGTH) - progress + if add_offset == 0 then add_offset = nil end + phase = nphase + state:set_int("date_offset", add_offset) +end + +-- set the moon's texture style for the given player +function moon_phases.set_style(player, style) + if style ~= "classic" and style ~= "realistic" then + return false + end + local meta_data = player:get_meta() + if style == DEFAULT_STYLE then style = nil end + meta_data:set_string("moon_phases:texture_style", style) + return true +end + +-- calculate the current sky layout for a given player +local function generate_effects(params) + local override = {} + + local time = params.time + local day = params.day_count + local date_offset = state:get_int("date_offset") + day = day + date_offset + if time > 0.5 then + day = day + 1 + end + + local meta_data = params.player:get_meta() + local style = meta_data:get_string("moon_phases:texture_style") + if style ~= "classic" and style ~= "realistic" then + style = TEXTURE_STYLE + end + + phase = ((math.ceil(day / PHASE_LENGTH) - 1) % PHASE_COUNT) + 1 + override["climate_api:skybox"] = { + moon_data = { + texture = "moon_" .. phase .. "_" .. style .. ".png", + scale = 0.8 + } + } + return override +end + +local function update_sky(player) + local params = {} + params.time = minetest.get_timeofday() + params.day_count = minetest.get_day_count() + params.player = player + local sky = generate_effects(params) + player:set_moon(sky.moon_data) +end + +local timer = 0 +local function handle_time_progression(dtime) + timer = timer + dtime + if timer < GSCYCLE then return end + for _, player in ipairs(minetest.get_connected_players()) do + update_sky(player) + end + timer = 0 +end + +if mod_climate_api then + -- register moon cycles as weather preset + climate_api.register_weather(name, {}, generate_effects) +else + -- set the moon texture of newly joined player + minetest.register_on_joinplayer(update_sky) + + -- check for changes and update player skies + minetest.register_globalstep(handle_time_progression) +end \ No newline at end of file diff --git a/init.lua b/init.lua index 5f19121..4b070d0 100644 --- a/init.lua +++ b/init.lua @@ -1,96 +1,132 @@ +local mod_climate_api = minetest.get_modpath("climate_api") ~= nil local mod_skylayer = minetest.get_modpath("skylayer") ~= nil local modpath = minetest.get_modpath("moon_phases"); local GSCYCLE = 0.5 -- global step cycle local DEFAULT_LENGTH = 4 -- default cycle length -local DEFAULT_STYLE = "realistic" -- default texture style +local DEFAULT_STYLE = "classic" -- default texture style +local PHASE_COUNT = 8 -- number of phases to go through + +-- retrieve mod configuration +local PHASE_LENGTH = 4--minetest.settings:get("moon_phases_cycle") or DEFAULT_LENGTH +local TEXTURE_STYLE = minetest.settings:get("moon_phases_style") or DEFAULT_STYLE + +local sky_color = { + "#1d293aff", + "#1c4b8dff", + nil, + "#579dffff", + nil, + "#1c4b8dff", + "#1d293aff", + "#000000ff" +} + +local horizon_color = { + "#243347ff", + "#235fb3ff", + nil, + "#73aeffff", + nil, + "#3079dfff", + "#173154ff", + "#000000ff" +} moon_phases = {} local state = minetest.get_mod_storage() -if not state:contains("day") then - state:from_table({fields = { - day = 1, - phase = 1, - change_time = 1 - }}) + +-- calculate current moon phase from date +-- and stored date offset +local function calculate_phase() + local time = minetest.get_timeofday() + local day = minetest.get_day_count() + state:get_int("date_offset") + if time > 0.5 then + day = day + 1 + end + return ((math.ceil(day / PHASE_LENGTH) - 1) % PHASE_COUNT) + 1 end --- retrieve mod configuration -local PHASE_LENGTH = minetest.settings:get("moon_phases_cycle") or DEFAULT_LENGTH -local TEXTURE_STYLE = minetest.settings:get("moon_phases_style") or DEFAULT_STYLE +local phase = 1 + +-- return the current moon phase +function moon_phases.get_phase() + return phase +end -- set the moon texture of a player to the given phase local function set_texture(player, phase) - local sl = {} + if not player.get_stars then return end -- check for new sky API local meta_data = player:get_meta() local style = meta_data:get_string("moon_phases:texture_style") if style ~= "classic" and style ~= "realistic" then style = TEXTURE_STYLE end local texture = "moon_" .. phase .. "_" .. style .. ".png" - sl.name = "moon_phases:custom" - sl.moon_data = { + local name = "moon_phases:cycle" + local sky = {} + sky.sky_data = { + type = "regular", + sky_color = { + night_sky = sky_color[phase], + night_horizon = horizon_color[phase] + } + } + sky.moon_data = { visible = true, texture = texture, scale = 0.8 } - if mod_skylayer then - skylayer.add_layer(player:get_player_name(), sl) + local playername = player:get_player_name() + if mod_climate_api then + sky.priority = 0 + climate_api.skybox.add_layer(playername, name, sky) + elseif mod_skylayer then + sky.name = name + skylayer.add_layer(playername, sky) else - player:set_moon(sl.moon_data) - end -end - --- update moon textures of all online players -local function update_textures() - local phase = state:get_int("phase") - for _, player in ipairs(minetest.get_connected_players()) do - set_texture(player, phase) + player:set_sky(sky.sky_data) + player:set_moon(sky.moon_data) end end -- check for day changes local function handle_time_progression() - local time = minetest.get_timeofday() - local day = state:get_int("day") - local phase = state:get_int("phase") - local change_time = state:get_int("change_time") == 1 - if time >= 0.5 and change_time then - day = day + 1 - state:set_int("day", day) - if day % PHASE_LENGTH == 0 then - state:set_int("phase", (phase % 8) + 1) - state:set_int("change_time", 0) - update_textures() + local n_phase = calculate_phase() + if n_phase ~= phase then + phase = n_phase + minetest.log(dump2(phase, "htp: phase")) + minetest.log(dump2(n_phase, "htp: n_phase")) + for _, player in ipairs(minetest.get_connected_players()) do + set_texture(player, phase) end - elseif time < 0.5 and not change_time then - state:set_int("change_time", 1) end end --- return the current moon phase -function moon_phases.get_phase() - return state:get_int("phase") -end - -- set the current moon phase --- @param phase int Phase between 1 and 8 -function moon_phases.set_phase(phase) - phase = math.floor(tonumber(phase)) - if (not phase) or phase < 1 or phase > 8 then +-- @param phase int Phase between 1 and PHASE_COUNT +function moon_phases.set_phase(nphase) + nphase = math.floor(tonumber(nphase)) + if (not nphase) or nphase < 1 or nphase > PHASE_COUNT then return false end - state:set_int("phase", phase) - update_textures() + local day = minetest.get_day_count() + local date_offset = state:get_int("date_offset") + local progress = (day + date_offset) % PHASE_LENGTH + local phase_offset = (nphase - phase + PHASE_COUNT) % PHASE_COUNT + local add_offset = ((phase_offset * PHASE_LENGTH) + date_offset - progress) + state:set_int("date_offset", add_offset) + handle_time_progression() return true end -- set the moon's texture style for the given player function moon_phases.set_style(player, style) - if style ~= "classic" and style ~= "realistic" then + if style ~= nil and style ~= "classic" and style ~= "realistic" then return false end + --if style == DEFAULT_STYLE then style = nil end local meta_data = player:get_meta() meta_data:set_string("moon_phases:texture_style", style) set_texture(player, state:get_int("phase")) @@ -99,12 +135,11 @@ end -- set the moon texture of newly joined player minetest.register_on_joinplayer(function(player) - local phase = state:get_int("phase") set_texture(player, phase) end) -- check for day changes and call handlers -local timer = 0 +local timer = math.huge minetest.register_globalstep(function(dtime) timer = timer + dtime if timer < GSCYCLE then return end diff --git a/mod.conf b/mod.conf index 61b692a..994f734 100644 --- a/mod.conf +++ b/mod.conf @@ -10,4 +10,4 @@ square vanilla themed 16x16px textures Requires at least Minetest 5.2.0 """ -optional_depends = skylayer \ No newline at end of file +optional_depends = climate_api, skylayer \ No newline at end of file diff --git a/settingtypes.txt b/settingtypes.txt index 55cf151..5272e6e 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -1,2 +1,2 @@ moon_phases_cycle (Change moon phase every X days) int 4 -moon_phases_style (Choose a default texture style) enum realistic classic,realistic \ No newline at end of file +moon_phases_style (Choose a default texture style) enum classic classic,realistic \ No newline at end of file diff --git a/textures/moon_1_classic.png b/textures/moon_1_classic.png index 2fd3f1b..2b67cc9 100644 Binary files a/textures/moon_1_classic.png and b/textures/moon_1_classic.png differ diff --git a/textures/moon_2_classic.png b/textures/moon_2_classic.png index 8107343..8860838 100644 Binary files a/textures/moon_2_classic.png and b/textures/moon_2_classic.png differ diff --git a/textures/moon_3_classic.png b/textures/moon_3_classic.png index e38175e..402ed45 100644 Binary files a/textures/moon_3_classic.png and b/textures/moon_3_classic.png differ diff --git a/textures/moon_4_classic.png b/textures/moon_4_classic.png index d674eee..5b3b70e 100644 Binary files a/textures/moon_4_classic.png and b/textures/moon_4_classic.png differ diff --git a/textures/moon_5_classic.png b/textures/moon_5_classic.png index 4536a3a..36abdd1 100644 Binary files a/textures/moon_5_classic.png and b/textures/moon_5_classic.png differ diff --git a/textures/moon_6_classic.png b/textures/moon_6_classic.png index 42c35d8..0640c77 100644 Binary files a/textures/moon_6_classic.png and b/textures/moon_6_classic.png differ diff --git a/textures/moon_7_classic.png b/textures/moon_7_classic.png index 14a3abe..0b44ad7 100644 Binary files a/textures/moon_7_classic.png and b/textures/moon_7_classic.png differ diff --git a/textures/moon_8_classic.png b/textures/moon_8_classic.png index 4d7beb8..cfc74f3 100644 Binary files a/textures/moon_8_classic.png and b/textures/moon_8_classic.png differ