2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
The gametime module handles the global passage of time in the mud.
|
|
|
|
|
|
|
|
|
|
It also supplies some useful methods to convert between
|
|
|
|
|
in-mud time and real-world time as well allows to get the
|
|
|
|
|
total runtime of the server and the current uptime.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from django.conf import settings
|
|
|
|
|
from src.scripts.scripts import Script
|
|
|
|
|
from src.scripts.models import ScriptDB
|
|
|
|
|
from src.utils.create import create_script
|
|
|
|
|
from src.utils import logger
|
|
|
|
|
|
|
|
|
|
# name of script that keeps track of the time
|
|
|
|
|
|
|
|
|
|
GAME_TIME_SCRIPT = "sys_game_time"
|
|
|
|
|
|
|
|
|
|
# Speed-up factor of the in-game time compared
|
2012-06-10 11:16:00 +02:00
|
|
|
# to real time.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
TIMEFACTOR = settings.TIME_FACTOR
|
|
|
|
|
|
2014-01-01 18:06:01 -08:00
|
|
|
# How often this script runs and updates the game time
|
|
|
|
|
|
|
|
|
|
UPDATE_INTERVAL = settings.TIME_UPDATE_INTERVAL
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
# Common real-life time measures, in seconds.
|
|
|
|
|
# You should not change these.
|
|
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
REAL_TICK = max(1.0, settings.TIME_TICK) # Smallest time unit (min 1s)
|
|
|
|
|
REAL_MIN = 60.0 # seconds per minute in real world
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
# Game-time units, in real-life seconds. These are supplied as
|
|
|
|
|
# a convenient measure for determining the current in-game time,
|
|
|
|
|
# e.g. when defining events. The words month, week and year can
|
|
|
|
|
# of course mean whatever units of time are used in the game.
|
|
|
|
|
|
2010-09-04 17:21:26 +00:00
|
|
|
TICK = REAL_TICK * TIMEFACTOR
|
2014-01-02 00:12:33 -08:00
|
|
|
MIN = settings.TIME_SEC_PER_MIN
|
2010-08-29 18:46:58 +00:00
|
|
|
HOUR = MIN * settings.TIME_MIN_PER_HOUR
|
|
|
|
|
DAY = HOUR * settings.TIME_HOUR_PER_DAY
|
|
|
|
|
WEEK = DAY * settings.TIME_DAY_PER_WEEK
|
|
|
|
|
MONTH = WEEK * settings.TIME_WEEK_PER_MONTH
|
|
|
|
|
YEAR = MONTH * settings.TIME_MONTH_PER_YEAR
|
|
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
class GameTime(Script):
|
|
|
|
|
"""
|
|
|
|
|
This sets up an script that keeps track of the
|
|
|
|
|
in-game time and some other time units.
|
|
|
|
|
"""
|
|
|
|
|
def at_script_creation(self):
|
|
|
|
|
"""
|
|
|
|
|
Setup the script
|
|
|
|
|
"""
|
|
|
|
|
self.key = "sys_game_time"
|
|
|
|
|
self.desc = "Keeps track of the game time"
|
2014-01-01 18:06:01 -08:00
|
|
|
self.interval = UPDATE_INTERVAL
|
2012-06-10 11:16:00 +02:00
|
|
|
self.persistent = True
|
|
|
|
|
self.start_delay = True
|
2013-11-14 19:31:17 +01:00
|
|
|
self.attributes.add("game_time", 0.0) # IC time
|
|
|
|
|
self.attributes.add("run_time", 0.0) # OOC time
|
|
|
|
|
self.attributes.add("up_time", 0.0) # OOC time
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
def at_repeat(self):
|
|
|
|
|
"""
|
|
|
|
|
Called every minute to update the timers.
|
2012-06-10 11:16:00 +02:00
|
|
|
"""
|
2010-08-29 18:46:58 +00:00
|
|
|
# We store values as floats to avoid drift over time
|
2013-08-25 16:41:18 +02:00
|
|
|
game_time = float(self.attributes.get("game_time"))
|
|
|
|
|
run_time = float(self.attributes.get("run_time"))
|
|
|
|
|
up_time = float(self.attributes.get("up_time"))
|
2014-01-01 18:06:01 -08:00
|
|
|
self.attributes.add("game_time", game_time + UPDATE_INTERVAL * TIMEFACTOR)
|
|
|
|
|
self.attributes.add("run_time", run_time + UPDATE_INTERVAL)
|
|
|
|
|
self.attributes.add("up_time", up_time + UPDATE_INTERVAL)
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
def at_start(self):
|
|
|
|
|
"""
|
|
|
|
|
This is called once every server restart.
|
2012-06-10 11:16:00 +02:00
|
|
|
We reset the up time.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2013-08-25 16:41:18 +02:00
|
|
|
self.attributes.add("up_time", 0.0)
|
2014-01-01 18:06:01 -08:00
|
|
|
self.interval = UPDATE_INTERVAL
|
2012-06-10 11:16:00 +02:00
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
# Access routines
|
|
|
|
|
|
2014-01-02 00:12:33 -08:00
|
|
|
def format(seconds, divisors, modify_seconds=True):
|
|
|
|
|
"""
|
|
|
|
|
Takes a list of divisors by which to divide the seconds, also passed
|
|
|
|
|
in, by. The result of each division will be returned in the order it
|
|
|
|
|
was performed, starting from the beginning of the divisors list.
|
|
|
|
|
|
|
|
|
|
The default behavior is to, after first dividing the number of seconds
|
|
|
|
|
by the divisor, mod the seconds by the divisor and, at the very end,
|
|
|
|
|
return the left over seconds by appending to the list. When passed a
|
|
|
|
|
list of divisors such as [31536000, 2628000, 604800, 86400, 3600, 60]
|
|
|
|
|
this results in the years, months, weeks, days, hours, minutes, and
|
|
|
|
|
seconds that have passed, according to ths seconds value passed in,
|
|
|
|
|
being returned via tuple.
|
|
|
|
|
|
|
|
|
|
If modify_seconds=False then the order the divisors are passed in
|
|
|
|
|
have no meaning other than placement in the results set and there is
|
|
|
|
|
no remainder to append to the end of the results.
|
|
|
|
|
"""
|
|
|
|
|
results = []
|
|
|
|
|
for divisor in divisors:
|
|
|
|
|
results.append(seconds / divisor)
|
|
|
|
|
if modify_seconds:
|
|
|
|
|
seconds = seconds % divisor
|
|
|
|
|
if modify_seconds:
|
|
|
|
|
results.append(seconds)
|
|
|
|
|
return tuple(results)
|
|
|
|
|
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def gametime_format(seconds):
|
|
|
|
|
"""
|
|
|
|
|
Converts the count in seconds into an integer tuple of the form
|
|
|
|
|
(years, months, weeks, days, hours, minutes, seconds) where
|
2012-06-10 11:16:00 +02:00
|
|
|
several of the entries may be 0.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
We want to keep a separate version of this (rather than just
|
|
|
|
|
rescale the real time once and use the normal realtime_format
|
2012-06-10 11:16:00 +02:00
|
|
|
below) since the admin might for example decide to change how many
|
2010-08-29 18:46:58 +00:00
|
|
|
hours a 'day' is in their game etc.
|
|
|
|
|
"""
|
2014-01-02 00:12:33 -08:00
|
|
|
return format(seconds, [YEAR, MONTH, WEEK, DAY, HOUR, MIN])
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def realtime_format(seconds):
|
|
|
|
|
"""
|
|
|
|
|
As gametime format, but with real time units
|
|
|
|
|
"""
|
2014-01-02 00:12:33 -08:00
|
|
|
return format(seconds, [31536000, 2628000, 604800, 86400, 3600, 60])
|
2012-06-10 11:16:00 +02:00
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def gametime(format=False):
|
|
|
|
|
"""
|
|
|
|
|
Find the current in-game time (in seconds) since the start of the mud.
|
|
|
|
|
The value returned from this function can be used to track the 'true'
|
|
|
|
|
in-game time since only the time the game has actually been active will
|
2012-06-10 11:16:00 +02:00
|
|
|
be adding up (ignoring downtimes).
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
format - instead of returning result in seconds, format to (game-) time
|
2012-06-10 11:16:00 +02:00
|
|
|
units.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
script = ScriptDB.objects.get_all_scripts(GAME_TIME_SCRIPT)[0]
|
2011-02-21 17:47:02 +00:00
|
|
|
except (KeyError, IndexError):
|
2010-08-29 18:46:58 +00:00
|
|
|
logger.log_trace("GameTime script not found.")
|
|
|
|
|
return
|
|
|
|
|
# we return this as an integer (second-precision is good enough)
|
2013-08-25 16:41:18 +02:00
|
|
|
game_time = int(script.attributes.get("game_time"))
|
2010-08-29 18:46:58 +00:00
|
|
|
if format:
|
|
|
|
|
return gametime_format(game_time)
|
2012-06-10 11:16:00 +02:00
|
|
|
return game_time
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def runtime(format=False):
|
|
|
|
|
"""
|
|
|
|
|
Get the total actual time the server has been running (minus downtimes)
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
script = ScriptDB.objects.get_all_scripts(GAME_TIME_SCRIPT)[0]
|
2011-02-21 17:47:02 +00:00
|
|
|
except (KeyError, IndexError):
|
2010-08-29 18:46:58 +00:00
|
|
|
logger.log_trace("GameTime script not found.")
|
|
|
|
|
return
|
|
|
|
|
# we return this as an integer (second-precision is good enough)
|
2013-08-25 16:41:18 +02:00
|
|
|
run_time = int(script.attributes.get("run_time"))
|
2010-08-29 18:46:58 +00:00
|
|
|
if format:
|
|
|
|
|
return realtime_format(run_time)
|
|
|
|
|
return run_time
|
|
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def uptime(format=False):
|
|
|
|
|
"""
|
|
|
|
|
Get the actual time the server has been running since last downtime.
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
script = ScriptDB.objects.get_all_scripts(GAME_TIME_SCRIPT)[0]
|
2011-02-21 17:47:02 +00:00
|
|
|
except (KeyError, IndexError):
|
2010-08-29 18:46:58 +00:00
|
|
|
logger.log_trace("GameTime script not found.")
|
|
|
|
|
return
|
|
|
|
|
# we return this as an integer (second-precision is good enough)
|
2013-08-25 16:41:18 +02:00
|
|
|
up_time = int(script.attributes.get("up_time"))
|
2010-08-29 18:46:58 +00:00
|
|
|
if format:
|
|
|
|
|
return realtime_format(up_time)
|
|
|
|
|
return up_time
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def gametime_to_realtime(secs=0, mins=0, hrs=0, days=0,
|
|
|
|
|
weeks=0, months=0, yrs=0):
|
|
|
|
|
"""
|
2013-11-14 19:31:17 +01:00
|
|
|
This method helps to figure out the real-world time it will take until an
|
|
|
|
|
in-game time has passed. E.g. if an event should take place a month later
|
|
|
|
|
in-game, you will be able to find the number of real-world seconds this
|
|
|
|
|
corresponds to (hint: Interval events deal with real life seconds).
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
Example:
|
2013-11-14 19:31:17 +01:00
|
|
|
gametime_to_realtime(days=2) -> number of seconds in real life from
|
|
|
|
|
now after which 2 in-game days will have passed.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2014-01-02 00:12:33 -08:00
|
|
|
real_time = (secs + mins * MIN + hrs * HOUR + days * DAY + weeks * WEEK + \
|
|
|
|
|
months * MONTH + yrs * YEAR) / TIMEFACTOR
|
2010-08-29 18:46:58 +00:00
|
|
|
return real_time
|
|
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def realtime_to_gametime(secs=0, mins=0, hrs=0, days=0,
|
|
|
|
|
weeks=0, months=0, yrs=0):
|
|
|
|
|
"""
|
2013-11-14 19:31:17 +01:00
|
|
|
This method calculates how large an in-game time a real-world time
|
|
|
|
|
interval would correspond to. This is usually a lot less interesting
|
|
|
|
|
than the other way around.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2012-06-10 11:16:00 +02:00
|
|
|
Example:
|
2010-08-29 18:46:58 +00:00
|
|
|
realtime_to_gametime(days=2) -> number of game-world seconds
|
|
|
|
|
corresponding to 2 real days.
|
|
|
|
|
"""
|
2013-11-14 19:31:17 +01:00
|
|
|
game_time = TIMEFACTOR * (secs + mins * 60 + hrs * 3600 + days * 86400 +
|
|
|
|
|
weeks * 604800 + months * 2419200 + yrs * 29030400)
|
2010-08-29 18:46:58 +00:00
|
|
|
return game_time
|
|
|
|
|
|
|
|
|
|
|
2012-06-10 11:16:00 +02:00
|
|
|
# Time administration routines
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
def init_gametime():
|
|
|
|
|
"""
|
|
|
|
|
This is called once, when the server starts for the very first time.
|
|
|
|
|
"""
|
2012-06-10 11:16:00 +02:00
|
|
|
# create the GameTime script and start it
|
2010-08-29 18:46:58 +00:00
|
|
|
game_time = create_script(GameTime)
|
|
|
|
|
game_time.start()
|