evennia/lib/utils/gametime.py

179 lines
5.8 KiB
Python

"""
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 time import time
from django.conf import settings
from src.scripts.scripts import Script
from src.utils.create import create_script
GAMETIME_SCRIPT_NAME = "sys_game_time"
# Speed-up factor of the in-game time compared
# to real time.
TIMEFACTOR = settings.TIME_FACTOR
# Common real-life time measure, in seconds.
# You should not change this.
REAL_MIN = 60.0 # seconds per minute in real world
# 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 in-game events. The words month, week and year can
# be used to mean whatever units of time are used in the game.
MIN = settings.TIME_SEC_PER_MIN
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
# Cached time stamps
SERVER_STARTTIME = time()
SERVER_RUNTIME = 0.0
class GameTime(Script):
"""
This script repeatedly saves server times so
it can be retrieved after server downtime.
"""
def at_script_creation(self):
"""
Setup the script
"""
self.key = GAMETIME_SCRIPT_NAME
self.desc = "Saves uptime/runtime"
self.interval = 60
self.persistent = True
self.start_delay = True
self.attributes.add("run_time", 0.0) # OOC time
self.attributes.add("up_time", 0.0) # OOC time
def at_repeat(self):
"""
Called every minute to update the timers.
"""
self.attributes.add("run_time", runtime())
self.attributes.add("up_time", uptime())
def at_start(self):
"""
This is called once every server restart.
We reset the up time and load the relevant
times.
"""
global SERVER_RUNTIME
SERVER_RUNTIME = self.attributes.get("run_time")
def save():
"Force save of time. This is called by server when shutting down/reloading."
from src.scripts.models import ScriptDB
try:
script = ScriptDB.objects.get(db_key=GAMETIME_SCRIPT_NAME)
script.at_repeat()
except Exception:
from src.utils import logger
logger.log_trace()
def _format(seconds, *divisors) :
"""
Helper function. Creates a tuple of even dividends given
a range of divisors.
Inputs
seconds - number of seconds to format
*divisors - a number of integer dividends. The number of seconds will be
integer-divided by the first number in this sequence, the remainder
will be divided with the second and so on.
Output:
A tuple of length len(*args)+1, with the last element being the last remaining
seconds not evenly divided by the supplied dividends.
"""
results = []
seconds = int(seconds)
for divisor in divisors:
results.append(seconds / divisor)
seconds %= divisor
results.append(seconds)
return tuple(results)
# Access functions
def runtime(format=False):
"Get the total runtime of the server since first start (minus downtimes)"
runtime = SERVER_RUNTIME + (time() - SERVER_STARTTIME)
if format:
return _format(runtime, 31536000, 2628000, 604800, 86400, 3600, 60)
return runtime
def uptime(format=False):
"Get the current uptime of the server since last reload"
uptime = time() - SERVER_STARTTIME
if format:
return _format(uptime, 31536000, 2628000, 604800, 86400, 3600, 60)
return uptime
def gametime(format=False):
"Get the total gametime of the server since first start (minus downtimes)"
gametime = runtime() * TIMEFACTOR
if format:
return _format(gametime, YEAR, MONTH, WEEK, DAY, HOUR, MIN)
return gametime
def gametime_to_realtime(secs=0, mins=0, hrs=0, days=0,
weeks=0, months=0, yrs=0, format=False):
"""
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).
Example:
gametime_to_realtime(days=2) -> number of seconds in real life from
now after which 2 in-game days will have passed.
"""
realtime = (secs + mins * MIN + hrs * HOUR + days * DAY + weeks * WEEK + \
months * MONTH + yrs * YEAR) / TIMEFACTOR
if format:
return _format(realtime, 31536000, 2628000, 604800, 86400, 3600, 60)
return realtime
def realtime_to_gametime(secs=0, mins=0, hrs=0, days=0,
weeks=0, months=0, yrs=0, format=False):
"""
This method calculates how much in-game time a real-world time
interval would correspond to. This is usually a lot less interesting
than the other way around.
Example:
realtime_to_gametime(days=2) -> number of game-world seconds
corresponding to 2 real days.
"""
gametime = TIMEFACTOR * (secs + mins * 60 + hrs * 3600 + days * 86400 +
weeks * 604800 + months * 2628000 + yrs * 31536000)
if format:
return _format(gametime, YEAR, MONTH, WEEK, DAY, HOUR, MIN)
return gametime
# Time administration routines
def init_gametime():
"""
This is called once, when the server starts for the very first time.
"""
# create the GameTime script and start it
game_time = create_script(GameTime)
game_time.start()