diff options
Diffstat (limited to 'advtrains_line_automation/railwaytime.lua')
-rw-r--r-- | advtrains_line_automation/railwaytime.lua | 308 |
1 files changed, 0 insertions, 308 deletions
diff --git a/advtrains_line_automation/railwaytime.lua b/advtrains_line_automation/railwaytime.lua deleted file mode 100644 index 258009e..0000000 --- a/advtrains_line_automation/railwaytime.lua +++ /dev/null @@ -1,308 +0,0 @@ --- railwaytime.lua --- Advtrains uses a desynchronized time for train movement. Everything is counted relative to this time counter. --- The advtrains-internal time is in no way synchronized to the real-life time, due to: --- - Lag --- - Server stops/restarts --- However, this means that implementing a "timetable" system using the "real time" is not practical. Therefore, --- we introduce a custom time system, the RWT(Railway Time), which has nothing to do with RLT(Real-Life Time) --- RWT has a time cycle of 1 hour. This should be sufficient for most train lines that will ever be built in Minetest. --- A RWT looks like this: 37;25 --- The ; is to distinguish it from a normal RLT (which has colons e.g. 12:34:56). Left number is minutes, right number is seconds. --- The minimum RWT is 00;00, the maximum is 59;59. --- It is OK to leave one places out at either end, esp. when writing relative times, such as: --- 43;3 22;0 2;30 0;10 ;10 --- Those places are then filled with zeroes. Indeed, ";" would be valid for 00;00 . - --- There is an "adapt mode", which was proposed by gpcf, and results in RWT automatically adapting itself to real-world time. --- It works by shifting the minute/second after the realtime minute/second, adjusting the cycle value as needed. - --- Using negative times is discouraged. If you need a negative time, you may insert a minus (-) ONLY in the "c" place - ---[[ -1;23;45 = { - s=45, - m=23, - c=1, -- Cycle(~hour), not displayed most time -} - -Railway times can exist in 3 forms: -- as table (see above) -- as string (like "12;34") -- as number (of seconds) - -Forms are automagically converted as needed by the converter functions to_* -To be sure a rwt is in the required form, explicitly use a converter. - -]] - -local rwt = {} - ---Time Stamp (Seconds since start of world) -local e_time = 0 -local e_has_loaded = false - -local setting_rwt_real = minetest.settings:get("advtrains_lines_rwt_realtime") -if setting_rwt_real=="" then - setting_rwt_real = "independent" -end - -local e_last_epoch -- last real-time timestamp - --- Advance RWT to match minute/second to the current real-world time --- only accounts for the minute/second part, leaves hour/cycle untouched -local function adapt_real_time() - local datetab = os.date("*t") - local real_sectotal = 60*datetab.min + datetab.sec - - local rwttab = rwt.now() - local rwt_sectotal = 60*rwttab.m + rwttab.s - - --calculate the difference and take it %3600 (seconds/hour) to always move forward - local secsfwd = (real_sectotal - rwt_sectotal) % 3600 - - atlog("[lines][rwt] Skipping",secsfwd,"seconds forward to sync rwt (",rwt.to_string(rwttab),") to real time (",os.date("%H:%M:%S"),")") - - e_time = e_time + secsfwd -end - -function rwt.set_time(t) - e_time = t or 0 - if setting_rwt_real == "adapt_real" then - adapt_real_time() - end - atlog("[lines][rwt] Initialized railway time: ",rwt.to_string(e_time)) - e_last_epoch = os.time() - - e_has_loaded = true -end - -function rwt.get_time() - return e_time -end - -function rwt.step(dt) - if not e_has_loaded then - rwt.set_time(0) - end - - if setting_rwt_real=="independent" then - -- Regular stepping with dtime - e_time = e_time + dt - else - -- advance with real-world time - local diff = os.time() - e_last_epoch - e_last_epoch = os.time() - - if diff>0 then - e_time = e_time + diff - end - end -end - -function rwt.now() - return rwt.to_table(e_time) -end - -function rwt.new(c, m, s) - return { - c = c or 0, - m = m or 0, - s = s or 0 - } -end -function rwt.copy(rwtime) - local rwtimet = rwt.to_table(rwtime) - return { - c = rwtimet.c or 0, - m = rwtimet.m or 0, - s = rwtimet.s or 0 - } -end - -function rwt.to_table(rwtime) - if type(rwtime) == "table" then - return rwtime - elseif type(rwtime) == "string" then - return rwt.parse(rwtime) - elseif type(rwtime) == "number" then - local res = {} - local seconds = atfloor(rwtime) - res.s = seconds % 60 - local minutes = atfloor(seconds/60) - res.m = minutes % 60 - res.c = atfloor(minutes/60) - return res - end -end - -function rwt.to_secs(rwtime, c_over) - local res = rwtime - if type(rwtime) == "string" then - res = rwt.parse(rwtime) - elseif type(rwtime) == "number" then - return rwtime - end - if type(res)=="table" then - return (c_over or res.c)*60*60 + res.m*60 + res.s - end -end - -function rwt.to_string(rwtime_p, no_cycle) - local rwtime = rwt.to_table(rwtime_p) - if rwtime.c~=0 and not no_cycle then - return string.format("%d;%02d;%02d", rwtime.c, rwtime.m, rwtime.s) - else - return string.format("%02d;%02d", rwtime.m, rwtime.s) - end -end - ---- - -local function v_n(str, cpl) - if not str then return nil end - if str == "" then - return 0 - end - local n = tonumber(str) - if not cpl and (n<0 or n>59) then - return nil - end - return n -end - -function rwt.parse(str) - --atdebug("parse",str) - --3-value form - local str_c, str_m, str_s = string.match(str, "^(%-?%d?%d?);(%d%d);(%d?%d?)$") - if str_c and str_m and str_s then - --atdebug("3v",str_c, str_m, str_s) - local c, m, s = v_n(str_c, true), v_n(str_m), v_n(str_s) - if c and m and s then - return rwt.new(c,m,s) - end - end - --2-value form - local str_m, str_s = string.match(str, "^(%d?%d?);(%d?%d?)$") - if str_m and str_s then - --atdebug("2v",str_m, str_s) - local m, s = v_n(str_m), v_n(str_s) - if m and s then - return rwt.new(0,m,s) - end - end -end - ---- - -function rwt.add(t1, t2) - local t1s = rwt.to_secs(t1) - local t2s = rwt.to_secs(t2) - return rwt.to_table(t1s + t2s) -end - --- How many seconds FROM t1 TO t2 -function rwt.diff(t1, t2) - local t1s = rwt.to_secs(t1) - local t2s = rwt.to_secs(t2) - return t2s - t1s -end - --- Subtract t2 from t1 (inverted argument order compared to diff()) -function rwt.sub(t1, t2) - return rwt.to_table(rwt.diff(t2, t1)) -end - --- Adjusts t2 by thresh and then returns time from t1 to t2 -function rwt.adj_diff(t1, t2, thresh) - local newc = rwt.adjust_cycle(t2, thresh, t1) - local t1s = rwt.to_secs(t1) - local t2s = rwt.to_secs(t2, newc) - return t1s - t2s -end - - - --- Threshold values --- "reftime" is the time to which this is made relative and defaults to now. -rwt.CA_FUTURE = 60*60 - 1 -- Selected so that time lies at or in the future of reftime (at nearest point in time) -rwt.CA_FUTURES = 60*60 -- Same, except when times are equal, advances one full cycle -rwt.CA_PAST = 0 -- Selected so that time lies at or in the past of reftime -rwt.CA_PASTS = -1 -- Same, except when times are equal, goes back one full cycle -rwt.CA_CENTER = 30*60 -- If time is within past 30 minutes of reftime, selected as past, else selected as future. - --- Adjusts the "cycle" value of a railway time to be in some relation to reftime. --- Returns new cycle -function rwt.adjust_cycle(rwtime, reftime_p, thresh) - local reftime = reftime_p or rwt.now() - - local reftimes = rwt.to_secs(reftime) - - local rwtimes = rwt.to_secs(rwtime, 0) - local timeres = reftimes + thresh - rwtimes - local cycles = atfloor(timeres / (60*60)) - - return cycles -end - -function rwt.adjust(rwtime, reftime, thresh) - local cp = rwt.copy(rwtime) - cp.c = rwt.adjust_cycle(rwtime, reftime, thresh) - return cp -end - --- Useful for departure times: returns time (in seconds) --- until the next (adjusted FUTURE) occurence of deptime is reached --- in this case, rwtime is used as reftime and deptime should lie in the future of rwtime --- rwtime defaults to NOW -function rwt.get_time_until(deptime, rwtime_p) - local rwtime = rwtime_p or rwt.now() - return rwt.adj_diff(rwtime, deptime, rwt.CA_FUTURE) -end - - --- Helper functions for handling "repeating times" (rpt) --- Those are generic declarations for time intervals like "every 5 minutes", with an optional offset --- ( /02;00-00;45 in timetable syntax - --- Get the time (in seconds) until the next time this rpt occurs -function rwt.time_to_next_rpt(rwtime, rpt_interval, rpt_offset) - local rpti_s = rwt.to_secs(rpt_interval) - - return (rpti_s - rwt.time_from_last_rpt(rwtime, rpti_s, rpt_offset)) % rpti_s - -- Modulo is just there to clip a false value of rpti_s to 0 -end - - --- Get the time (in seconds) since the last time this rpt occured -function rwt.time_from_last_rpt(rwtime, rpt_interval, rpt_offset) - local rwtime_s = rwt.to_secs(rwtime) - local rpti_s = rwt.to_secs(rpt_interval) - local rpto_s = rwt.to_secs(rpt_offset) - - return ((rwtime_s - rpto_s) % rpti_s) -end - --- From rwtime, get the next time that is divisible by rpt_interval offset by rpt_offset -function rwt.next_rpt(rwtime, rpt_interval, rpt_offset) - local rwtime_s = rwt.to_secs(rwtime) - local rpti_s = rwt.to_secs(rpt_interval) - local time_from_last = rwt.time_from_last_rpt(rwtime_s, rpti_s, rpt_offset) - - local res_s = rwtime_s - time_from_last + rpti_s - - return rwt.to_table(res_s) -end - --- from rwtime, get the last time that this rpt matched (which is actually just next_rpt - rpt_offset -function rwt.last_rpt(rwtime, rpt_interval, rpt_offset) - local rwtime_s = rwt.to_sec(rwtime) - local rpti_s = rwt.to_sec(rpt_interval) - local time_from_last = rwt.time_from_last_rpt(rwtime, rpt_interval, rpt_offset) - - local res_s = rwtime_s - time_from_last - - return rwt.to_table(res_s) -end - - -advtrains.lines.rwt = rwt |