1 local modname = minetest.get_current_modname()
2 local storage = minetest.get_mod_storage()
3 local S = minetest.get_translator("lmz_opening_hours")
7 local opening_hours_default = {
10 day0_start_minute = 0,
14 day1_start_minute = 0,
18 day2_start_minute = 0,
22 day3_start_minute = 0,
26 day4_start_minute = 0,
30 day5_start_minute = 0,
34 day6_start_minute = 0,
41 local warn_cooldown = 0
43 local function get_date()
47 local function get_date_formated()
48 return os.date("%d.%m.%y")
51 local function upgrade_configuration(old)
54 day0_start_hour = tonumber(old.weekend_start),
55 day0_start_minute = 0,
56 day0_end_hour = tonumber(old.weekend_end),
58 day1_start_hour = tonumber(old.weekday_start),
59 day1_start_minute = 0,
60 day1_end_hour = tonumber(old.weekday_end),
62 day2_start_hour = tonumber(old.weekday_start),
63 day2_start_minute = 0,
64 day2_end_hour = tonumber(old.weekday_end),
66 day3_start_hour = tonumber(old.weekday_start),
67 day3_start_minute = 0,
68 day3_end_hour = tonumber(old.weekday_end),
70 day4_start_hour = tonumber(old.weekday_start),
71 day4_start_minute = 0,
72 day4_end_hour = tonumber(old.weekday_end),
74 day5_start_hour = tonumber(old.weekday_start),
75 day5_start_minute = 0,
76 day5_end_hour = tonumber(old.weekday_end),
78 day6_start_hour = tonumber(old.weekend_start),
79 day6_start_minute = 0,
80 day6_end_hour = tonumber(old.weekend_end),
82 warn_offset = tonumber(old.warn_offset),
83 warn_interval = tonumber(old.warn_interval)
86 new.exception_today = old.today
87 new.exception_start_hour = old.today_start
88 new.exception_start_minute = 0
89 new.exception_end_hour = old.today_end
90 new.exception_end_minute = 0
95 local function save_data()
96 storage:from_table({fields = opening_hours})
99 local function load_data()
100 opening_hours = storage:to_table().fields
101 if opening_hours.weekday_start then
102 opening_hours = upgrade_configuration(opening_hours)
103 elseif not opening_hours.version then
104 opening_hours = opening_hours_default
108 local function reset_execption()
109 opening_hours.exception_today = nil
112 local function opening_today()
113 local exception = opening_hours.exception_today
115 if exception and exception == get_date_formated() then
116 day_key = "exception"
118 local d = os.date("%w")
122 start_hour = opening_hours[day_key .. "_start_hour"],
123 start_minute = opening_hours[day_key .. "_start_minute"],
124 end_hour = opening_hours[day_key .. "_end_hour"],
125 end_minute = opening_hours[day_key .. "_end_minute"]
129 local function create_exception()
130 local today = opening_today()
131 opening_hours.exception_today = get_date_formated()
132 opening_hours.exception_start_hour = today.start_hour
133 opening_hours.exception_start_minute = today.start_minute
134 opening_hours.exception_end_hour = today.end_hour
135 opening_hours.exception_end_minute = today.end_minute
138 local function tick(dtime)
140 local exception = opening_hours.exception_today
141 if exception and exception ~= get_date_formated() then
144 local today = opening_today()
145 local end_time = today.end_hour * 60 + today.end_minute
146 local now_time = d.hour * 60 + d.min
147 local minutes_remaining = end_time - now_time
148 if 0 < minutes_remaining
149 and minutes_remaining <= opening_hours.warn_offset then
150 if warn_cooldown <= 0 then
151 minetest.chat_send_all(minetest.colorize("#FF4D00", S("The server will close in @1 minutes.", minutes_remaining)))
152 warn_cooldown = tonumber(opening_hours.warn_interval) * 60
154 warn_cooldown = warn_cooldown - dtime
156 elseif minutes_remaining <= 0 then
157 for _, player in pairs(minetest.get_connected_players()) do
158 local name = player:get_player_name()
159 if not minetest.check_player_privs(name, {server = true}) then
160 minetest.kick_player(name, S("The server is closing!"))
166 local function on_join(name)
167 if minetest.check_player_privs(name, {server = true}) then return end
168 local today = opening_today()
170 local start_time = today.start_hour * 60 + today.start_minute
171 local end_time = today.end_hour * 60 + today.end_minute
172 local now_time = d.hour * 60 + d.min
173 local diff = start_time - now_time
175 return S("You visited outside of the opening hours") .. ". " .. S("The server will open again in @1 hours", math.ceil(diff / 60)) .. "."
176 elseif end_time <= now_time then
177 return S("You visited outside of the opening hours") .. ". " .. S("The server has already closed and will open again tomorrow") .. "."
181 local minute_step = 5
183 local function show_gui(name)
185 local fld_h = 0.82429501084599
186 local fld_sz = fld_w .. "," .. fld_h
187 local inline_off = 0.2427394885132
188 local lab_close_y = 6.3935847420893
189 local fld_close_y = lab_close_y + 0.2427394885132
190 local pre_colon_off = 0.4
191 local minute_off = 0.04
198 x.day1.fld_f_hour = 0.64
199 x.day1.fld_f_minute = x.day1.fld_f_hour + fld_w - minute_off
200 x.day1.lab_f_colon = x.day1.fld_f_minute - pre_colon_off
201 x.day1.fld_t_hour = x.day1.lab_f_colon + to_off
202 x.day1.fld_t_minute = x.day1.fld_t_hour + fld_w - minute_off
203 x.day1.lab_t_colon = x.day1.fld_t_minute - pre_colon_off
208 for k, v in pairs(x["day" .. last]) do
209 x["day" .. day][k] = v + day_off
214 local below_off = 1.1530125704378
215 local lab_b_y = 0.28175119202427
216 local fld_b_y = lab_b_y + below_off
217 local lab_b_colon_y = fld_b_y - inline_off
218 local lab_w_y = 2.0156046814044
219 local fld_w_y = lab_w_y + below_off
220 local lab_w_colon_y = fld_w_y - inline_off
221 local lab_e_y = 3.7494581707846
222 local fld_e_y = lab_e_y + below_off
223 local lab_e_colon_y = fld_e_y - inline_off
224 local o = opening_hours
225 local day_abbreviations = {
234 local formspec_business_days = ""
236 formspec_business_days = formspec_business_days
237 .. "label[" .. x["day" .. day].lab .. "," .. lab_b_y .. ";" .. day_abbreviations[day] .. "]"
238 .. "field[" .. x["day" .. day].fld_f_hour .. "," .. fld_b_y .. ";" .. fld_sz .. ";fld_day" .. day .. "_start_hour;" .. S("from") .. ";" .. string.format("%02d", o["day" .. day .. "_start_hour"]) .. "]"
239 .. "label[" .. x["day" .. day].lab_f_colon .. "," .. lab_b_colon_y .. ";:]"
240 .. "field[" .. x["day" .. day].fld_f_minute .. "," .. fld_b_y .. ";" .. fld_sz .. ";fld_day" .. day .. "_start_minute;;" .. string.format("%02d", o["day" .. day .. "_start_minute"]) .. "]"
241 .. "field[" .. x["day" .. day].fld_t_hour .. "," .. fld_b_y .. ";" .. fld_sz .. ";fld_day" .. day .. "_end_hour;" .. S("to") .. ";" .. string.format("%02d", o["day" .. day .. "_end_hour"]) .. "]"
242 .. "label[" .. x["day" .. day].lab_t_colon .. "," .. lab_b_colon_y .. ";:]"
243 .. "field[" .. x["day" .. day].fld_t_minute .. "," .. fld_b_y .. ";" .. fld_sz .. ";fld_day" .. day .. "_end_minute;;" .. string.format("%02d", o["day" .. day .. "_end_minute"]) .. "]"
245 local formspec_weekend = ""
248 formspec_weekend = formspec_weekend
249 .. "label[" .. x["day" .. col].lab .. "," .. lab_w_y .. ";" .. day_abbreviations[day] .. "]"
250 .. "field[" .. x["day" .. col].fld_f_hour .. "," .. fld_w_y .. ";" .. fld_sz .. ";fld_day" .. day .. "_start_hour;" .. S("from") .. ";" .. string.format("%02d", o["day" .. day .. "_start_hour"]) .. "]"
251 .. "label[" .. x["day" .. col].lab_f_colon .. "," .. lab_w_colon_y .. ";:]"
252 .. "field[" .. x["day" .. col].fld_f_minute .. "," .. fld_w_y .. ";" .. fld_sz .. ";fld_day" .. day .. "_start_minute;;" .. string.format("%02d", o["day" .. day .. "_start_minute"]) .. "]"
253 .. "field[" .. x["day" .. col].fld_t_hour .. "," .. fld_w_y .. ";" .. fld_sz .. ";fld_day" .. day .. "_end_hour;" .. S("to") .. ";" .. string.format("%02d", o["day" .. day .. "_end_hour"]) .. "]"
254 .. "label[" .. x["day" .. col].lab_t_colon .. "," .. lab_w_colon_y .. ";:]"
255 .. "field[" .. x["day" .. col].fld_t_minute .. "," .. fld_w_y .. ";" .. fld_sz .. ";fld_day" .. day .. "_end_minute;;" .. string.format("%02d", o["day" .. day .. "_end_minute"]) .. "]"
257 local formspec_exception = (o.exception_today
259 .. "label[" .. x.day1.lab .. "," .. lab_e_y .. ";" .. S("Today") .. "]"
260 .. "field[" .. x.day1.fld_f_hour .. "," .. fld_e_y .. ";" .. fld_sz .. ";fld_exception_start_hour;" .. S("from") .. ";" .. string.format("%02d", o.exception_start_hour) .. "]"
261 .. "label[" .. x.day1.lab_f_colon .. "," .. lab_e_colon_y .. ";:]"
262 .. "field[" .. x.day1.fld_f_minute .. "," .. fld_e_y .. ";" .. fld_sz .. ";fld_exception_start_minute;;" .. string.format("%02d", o.exception_start_minute) .. "]"
263 .. "field[" .. x.day1.fld_t_hour .. "," .. fld_e_y .. ";" .. fld_sz .. ";fld_exception_end_hour;" .. S("to") .. ";" .. string.format("%02d", o.exception_end_hour) .. "]"
264 .. "label[" .. x.day1.lab_t_colon .. "," .. lab_e_colon_y .. ";:]"
265 .. "field[" .. x.day1.fld_t_minute .. "," .. fld_e_y .. ";" .. fld_sz .. ";fld_exception_end_minute;;" .. string.format("%02d", o.exception_end_minute) .. "]"
266 or "image_button[0.34,4.5296922410056;4.205,0.7835;;add_exception;" .. S("Add exception") .. "]"
268 local formspec = "size[18.01,7.9267895878525]"
269 .. "label[-0.14,-0.23840485478977;" .. S("Opening hours") .. "]"
270 .. formspec_business_days
272 .. formspec_exception
273 .. "label[" .. x.day1.lab .. ",5.4833116601647;" .. S("Settings") .. "]"
274 .. "label[0.34," .. lab_close_y .. ";Spieler ]"
275 .. "field[1.6," .. fld_close_y .. ";" .. fld_sz .. ";fld_warn_offset;;" .. o.warn_offset .. "]"
276 .. "label[2.18," .. lab_close_y .. ";Minuten vor Ablauf der Zeit alle]"
277 .. "field[6.0," .. fld_close_y .. ";" .. fld_sz .. ";fld_warn_interval;;" .. o.warn_interval .. "]"
278 .. "label[6.6," .. lab_close_y .. ";Minuten warnen.]"
279 .. "image_button[5.14,7.6072821846554;2.605,0.7835;;save;" .. S("Save") .. "]"
280 .. "image_button_exit[7.62,7.6072821846554;2.605,0.7835;;close;" .. S("Close") .. "]"
281 minetest.show_formspec(name, "lmz_opening_hours:gui", formspec)
284 local function progress_gui_input(player, formname, fields)
285 local name = player:get_player_name()
286 if formname ~= "lmz_opening_hours:gui" or not minetest.check_player_privs(name, {server = true}) then return end
287 if fields.add_exception then
290 for k, v in pairs(fields) do
291 if k:sub(1, 4) == "fld_" then
292 local field = k:gsub("fld_", "")
293 local old = opening_hours[field]
294 opening_hours[field] = tonumber(v) or old
297 for k, v in pairs(opening_hours) do
298 if k:match("_hour$") then
299 opening_hours[k] = math.max(0, math.min(23, v))
300 elseif k:match("_minute$") then
301 opening_hours[k] = math.max(
305 minute_step * math.floor(
306 v / minute_step + 0.5
312 for k, v in pairs(opening_hours) do
313 if k:match("_end_hour$") then
314 local start = opening_hours[k:gsub("_end_", "_start_")]
316 opening_hours[k] = start
318 elseif k:match("_end_minute$") then
319 local hour_k = k:gsub("_minute$", "_hour")
320 local hour_start_k = hour_k:gsub("_end_", "_start_")
321 local start_k = k:gsub("_end_", "_start_")
322 if opening_hours[hour_start_k] >= opening_hours[hour_k]
323 and opening_hours[start_k] > v then
324 opening_hours[k] = opening_hours[start_k]
328 if not fields.quit and not fields.close then show_gui(name) end
333 minetest.register_globalstep(tick)
334 minetest.register_on_shutdown(save_data)
335 minetest.register_on_prejoinplayer(on_join)
336 minetest.register_chatcommand(
339 privs = {server = true},
340 description = S("Configure the opening hours"),
344 minetest.register_chatcommand(
347 privs = {server = true},
348 description = S("Configure the opening hours"),
352 minetest.register_on_player_receive_fields(progress_gui_input)