From 4e59fcf5c1e40dee764317a1190dceadc3a77829 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Sun, 6 Mar 2016 12:02:21 -0800 Subject: [PATCH] Add consistent monotonic day counter - get_day_count() I've written several experimental bits of code that revolve around the need for a consistent calendar, but implementing one is extremely hard in mods due to time changes and mods overriding core.get_timeofday(), which will conflict. The second part of the problem is that doing this from a mod requires constant maintenance of a settings file. An implementation in core is trivial, however, and solves all of these problems at virtually no cost: No extra branches in server steps, and a single branch when minetest.set_time_of_day(), which is entirely reasonable. We store the day_count value in env_meta.txt. The use case is obvious: This change allows mods to create an actual virtual calendar, or properly account for seasonal changes, etc.. We add a "/days" chatcommand that displays the current day count. No permissions are needed. It can only retrieve the day count, not modify it. --- builtin/game/chatcommands.lua | 7 +++++++ doc/lua_api.txt | 2 ++ src/environment.cpp | 20 +++++++++++++++++++- src/environment.h | 5 +++++ src/script/lua_api/l_env.cpp | 10 ++++++++++ src/script/lua_api/l_env.h | 3 +++ 6 files changed, 46 insertions(+), 1 deletion(-) diff --git a/builtin/game/chatcommands.lua b/builtin/game/chatcommands.lua index 2c7a0b532..0b1976640 100644 --- a/builtin/game/chatcommands.lua +++ b/builtin/game/chatcommands.lua @@ -785,6 +785,13 @@ core.register_chatcommand("time", { end, }) +core.register_chatcommand("days", { + description = "Display day count", + func = function(name, param) + return true, "Current day is " .. core.get_day_count() + end +}) + core.register_chatcommand("shutdown", { description = "shutdown server", privs = {server=true}, diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 65af51578..e2ab65ddc 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1998,6 +1998,8 @@ and `minetest.auth_reload` call the authetification handler. * `val` is between `0` and `1`; `0` for midnight, `0.5` for midday * `minetest.get_timeofday()` * `minetest.get_gametime()`: returns the time, in seconds, since the world was created +* `minetest.get_day_count()`: returns number days elapsed since world was created, + * accounting for time changes. * `minetest.find_node_near(pos, radius, nodenames)`: returns pos or `nil` * `radius`: using a maximum metric * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"` diff --git a/src/environment.cpp b/src/environment.cpp index 6da376a15..0d00ed170 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -208,6 +208,8 @@ void Environment::setDayNightRatioOverride(bool enable, u32 value) void Environment::setTimeOfDay(u32 time) { MutexAutoLock lock(this->m_time_lock); + if (m_time_of_day > time) + m_day_count++; m_time_of_day = time; m_time_of_day_f = (float)time / 24000.0; } @@ -238,8 +240,10 @@ void Environment::stepTimeOfDay(float dtime) bool sync_f = false; if (units > 0) { // Sync at overflow - if (m_time_of_day + units >= 24000) + if (m_time_of_day + units >= 24000) { sync_f = true; + m_day_count++; + } m_time_of_day = (m_time_of_day + units) % 24000; if (sync_f) m_time_of_day_f = (float)m_time_of_day / 24000.0; @@ -256,6 +260,13 @@ void Environment::stepTimeOfDay(float dtime) } } +u32 Environment::getDayCount() +{ + // Atomic counter + return m_day_count; +} + + /* ABMWithState */ @@ -727,6 +738,7 @@ void ServerEnvironment::saveMeta() args.setU64("lbm_introduction_times_version", 1); args.set("lbm_introduction_times", m_lbm_mgr.createIntroductionTimesString()); + args.setU64("day_count", m_day_count); args.writeLines(ss); ss<<"EnvArgsEnd\n"; @@ -792,6 +804,12 @@ void ServerEnvironment::loadMeta() } m_lbm_mgr.loadIntroductionTimes(lbm_introduction_times, m_gamedef, m_game_time); + try { + m_day_count = args.getU64("day_count"); + } catch (SettingNotFoundException &e) { + // If missing, start the day counter + m_day_count = 0; + } } void ServerEnvironment::loadDefaultMeta() diff --git a/src/environment.h b/src/environment.h index 448ed70e6..9b91a0928 100644 --- a/src/environment.h +++ b/src/environment.h @@ -95,6 +95,8 @@ public: void setDayNightRatioOverride(bool enable, u32 value); + u32 getDayCount(); + // counter used internally when triggering ABMs u32 m_added_objects; @@ -117,6 +119,9 @@ protected: // Overriding the day-night ratio is useful for custom sky visuals bool m_enable_day_night_ratio_override; u32 m_day_night_ratio_override; + // Days from the server start, accounts for time shift + // in game (e.g. /time or bed usage) + Atomic m_day_count; /* * Above: values managed by m_time_lock */ diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index f4ddc2afc..af89da9a1 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -561,6 +561,15 @@ int ModApiEnvMod::l_get_timeofday(lua_State *L) return 1; } +// get_day_count() -> int +int ModApiEnvMod::l_get_day_count(lua_State *L) +{ + GET_ENV_PTR; + + lua_pushnumber(L, env->getDayCount()); + return 1; +} + // get_gametime() int ModApiEnvMod::l_get_gametime(lua_State *L) { @@ -1055,6 +1064,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top) API_FCT(set_timeofday); API_FCT(get_timeofday); API_FCT(get_gametime); + API_FCT(get_day_count); API_FCT(find_node_near); API_FCT(find_nodes_in_area); API_FCT(find_nodes_in_area_under_air); diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index 0e385ffef..89dd7978f 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -113,6 +113,9 @@ private: // get_gametime() static int l_get_gametime(lua_State *L); + // get_day_count() -> int + static int l_get_day_count(lua_State *L); + // find_node_near(pos, radius, nodenames) -> pos or nil // nodenames: eg. {"ignore", "group:tree"} or "default:dirt" static int l_find_node_near(lua_State *L); -- 2.25.1